ecere/ListBox: Fixed clickedRow on Clear(); fixed a return value in DataField::positi...
[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             currentRow.selectedFlag = selected;
1879
1880             clickedRow = row;
1881          }
1882          else if(currentRow)
1883             currentRow.selectedFlag = selected;
1884
1885          if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
1886             SetScrollPosition(scroll.x,
1887                currentRow.index * rowHeight - height + rowHeight);
1888          else if(!currentRow || currentRow.index * rowHeight < scroll.y)
1889          {
1890             int line = currentRow ? currentRow.index * rowHeight : 0;
1891             //SNAPUP(line, rowHeight);
1892             SetScrollPosition(scroll.x, line);
1893          }
1894
1895          if(notify)
1896          {
1897             Window master = this.master;
1898             if(master)
1899             {
1900                if(style.freeSelect && visible)
1901                   NotifyHighlight(master, this, currentRow ? currentRow : null, 0);
1902                else
1903                   NotifySelect(master, this, currentRow ? currentRow : null, 0);
1904                if(style.alwaysEdit && currentRow)
1905                   currentRow.Edit(currentField);
1906             }
1907          }
1908
1909          Update(null);
1910       }
1911    }
1912
1913    void PopupEditBox(DataField whichField, bool repositionOnly)
1914    {
1915       if((!editData || !editData.visible || currentField != whichField) && currentRow)
1916       {
1917          // true: destroy edit box
1918          HideEditBox(true, true, false);
1919          if(whichField)
1920          {
1921             int height = rowHeight - (style.alwaysEdit ? 1 : 0);
1922             int x = 0;
1923             int y = currentRow.index * rowHeight + (style.header ? rowHeight : 0);
1924             int width;
1925             //void * data = currentRow.GetData(whichField);
1926             DataField field;
1927             DataRow row = null;
1928             ListBoxCell cell;
1929
1930             if(style.collapse && !(style.treeBranch))
1931                x += 15;
1932
1933             for(field = fields.first; field; field = field.next)
1934             {
1935                width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
1936                   clientSize.w - field.x : (field.width + EXTRA_SPACE);
1937                if(field == whichField) break;
1938                x += width;
1939             }
1940
1941             currentField = whichField;
1942             cell = GetCell(&row, &currentField);
1943
1944             if(!editData)
1945             {
1946                editData = DataBox
1947                {
1948                   this;
1949                   background = dataBoxBackground;
1950                   foreground = dataBoxForeground;
1951
1952                   bool NotifyChanged(bool closingDropDown)
1953                   {
1954                      DataRow row = null;
1955                      DataField field = null;
1956                      ListBoxCell cell = GetCell(&row, &field);
1957                      if(cell)
1958                      {
1959                         cell.isSet = true;
1960                         modifiedDocument = true;
1961                         Update(null);
1962                         NotifyChanged(master, this, currentRow);
1963                      }
1964                      return true;
1965                   }
1966
1967                   bool NotifyModified()
1968                   {
1969                      //DataRow row = null;
1970                      //DataField field = null;
1971                      //ListBoxCell cell = GetCell(&row, &field);
1972                      //cell.isSet = true;
1973                      modifiedDocument = true;
1974                      //Update(null);
1975                      NotifyModified(master, this, currentRow);
1976                      return true;
1977                   }
1978
1979                   bool OnKeyDown(Key key, unichar ch)
1980                   {
1981                      bool result = DataBox::OnKeyDown(key, ch);
1982                      if(visible && active)   // Added this check here, because we will not use enter/escape otherwise, and lose DataBox's result
1983                      {
1984                         if((SmartKey)key == enter || (SmartKey)key == escape) 
1985                            return true;
1986                      }
1987                      return result;
1988                   }
1989                };
1990                incref editData;
1991             }
1992             else
1993                editData.Destroy(0);
1994             editData.type = whichField.dataType;
1995             editData.fieldData = whichField.userData;
1996             editData.borderStyle = style.alwaysEdit ? 0 : deep;
1997             editData.data = cell ? cell.data : null;
1998
1999             if(!repositionOnly)
2000                // Might not really need this anymore...
2001                NotifyEditing(master, this, currentRow);
2002
2003             editData.Create();
2004             if(!style.alwaysEdit)
2005             {
2006                editData.position = { x, y - editData.clientStart.y };
2007                editData.size = { width, height + editData.clientStart.y * 2 };
2008             }
2009             else
2010             {
2011                editData.position = { x, y };
2012                editData.size = { width, height };
2013             }
2014             if(!repositionOnly)
2015                editData.Refresh();
2016             editData.visible = true;
2017
2018             if(style.alwaysEdit)
2019                editData.Deactivate();
2020
2021             //   MOVED THIS HIGHER FOR DATALIST EDITOR
2022             if(!repositionOnly)
2023                // Might not really need this anymore...
2024                NotifyEdited(master, this, currentRow);
2025          }
2026       }
2027    }
2028
2029    void OnRedraw(Surface surface)
2030    {
2031       DataRow row;
2032       int y = (style.header) ? rowHeight : 0;
2033       bool isActive = active;
2034       Font font = fontObject;
2035       Font boldFont = this.boldFont.font;
2036
2037       // Draw gray grid
2038       if(style.alwaysEdit && style.fullRowSelect)
2039       {
2040          // Horizontal lines
2041          int y = (style.header) ? rowHeight : 0;
2042          int x = -scroll.x - 1;// + EXTRA_SPACE;// / 2 - 1;
2043          int w = clientSize.w;
2044          int h = clientSize.h;
2045          DataRow row;
2046          DataField field;
2047
2048          // Fill out indent column
2049          if(style.collapse && !(style.treeBranch) && rows.first)
2050          {
2051             x += 15;
2052             surface.SetBackground(activeBorder);
2053             surface.Area(-scroll.x, 0, x, clientSize.h);
2054          }
2055
2056          surface.SetForeground(activeBorder);
2057          for(row = firstRowShown; row; row = row.GetNextRow())
2058          {
2059             y += rowHeight;
2060             surface.HLine(x + 1, w-1, y-1);
2061             if(y >= h)
2062                break;
2063          }
2064
2065          // Vertical lines
2066          for(field = fields.first; field; field = field.next)
2067          {
2068             int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
2069                clientSize.w - field.x : (field.width + EXTRA_SPACE);
2070             if(field.prev && y > 0)
2071                surface.VLine(0, y-1, x);
2072             x += width;
2073          }
2074       }
2075
2076       surface.foreground = this.foreground;
2077       surface.TextOpacity(false);
2078
2079       // Draw the tree branches
2080       if(style.treeBranch)
2081       {
2082          int y = -scroll.y + ((style.header) ? rowHeight : 0);
2083          surface.LineStipple(0x5555);
2084          surface.SetForeground(branchesColor);
2085          for(row = rows.first; row; row = row.GetNextRow() )
2086          {
2087             int x = -scroll.x + EXTRA_SPACE / 2-1;
2088             int rowStart = -scroll.x;
2089             int indent = 0;
2090             DataRow parent;
2091             int plusIndent;
2092
2093             for(parent = row.parent; parent; parent = parent.parent)
2094                if(!parent.header) indent += 20;
2095             if(style.rootCollapse) indent += 20;
2096
2097             plusIndent = (style.treeBranch) ? (indent - 20 + 4) : indent;
2098
2099             x += indent;
2100
2101             // Vertical line
2102             if(row.subRows.first)
2103             {
2104                int numRows = 0;
2105                int y1 = y + PLUSY + 4;
2106                int y2;
2107                DataRow child;
2108             
2109                for(child = row.collapsed ? null : row.subRows.first; child && child != row; )
2110                {
2111                   numRows++;
2112                   if(child.subRows.first && !child.collapsed && child != row.subRows.last)
2113                      child = child.subRows.first;
2114                   else if(child.next)
2115                      child = child.next;
2116                   else
2117                   {
2118                      for(; child && child != row; child = child.parent)
2119                      {
2120                         if(child.next)
2121                         {
2122                            child = child.next;
2123                            break;
2124                         }
2125                      }
2126                   }
2127                }
2128                y2 = y + numRows * rowHeight + PLUSY + 4;
2129                surface.VLine(y1, y2, rowStart + plusIndent + 7 + 20);
2130             }
2131             surface.HLine(rowStart + plusIndent + 7, rowStart + indent, y + PLUSY + 4);
2132
2133             y += rowHeight;
2134             if(y >= clientSize.h)
2135                break;
2136          }
2137          // Root Vertical Lines
2138          if(style.rootCollapse && rows.first)
2139          {
2140             int numRows = 0;
2141             int y1, y2;
2142             DataRow child;
2143             y = -scroll.y + ((style.header) ? rowHeight : 0);
2144             y1 = y + PLUSY + 4;
2145             for(child = rows.first; child && child != rows.last; )
2146             {
2147                numRows++;
2148                if(child.subRows.first && !child.collapsed && child != rows.last)
2149                   child = child.subRows.first;
2150                else if(child.next)
2151                   child = child.next;
2152                else
2153                {
2154                   for(; child; child = child.parent)
2155                   {
2156                      if(child.next)
2157                      {
2158                         child = child.next;
2159                         break;
2160                      }
2161                   }
2162                }
2163             }
2164             y2 = y + numRows * rowHeight + PLUSY + 4;
2165             surface.VLine(y1, y2, -scroll.x + 11);
2166          }
2167          surface.LineStipple(0);
2168       }
2169
2170       for(row = firstRowShown; row; row = row.GetNextRow() )
2171       {
2172          int x = -scroll.x + EXTRA_SPACE / 2-1;
2173          DataField field;
2174          ListBoxCell cell;
2175          Color foreground = this.foreground /*black*/, background = this.background /*white*/;
2176          DataDisplayFlags dataDisplayFlags = 0;
2177          int rowStart = -scroll.x;
2178          int indent = 0;
2179          DataRow parent;
2180          Bitmap icon = row.icon ? row.icon.bitmap : null;
2181          int collapseRowStart;
2182
2183          for(parent = row.parent; parent; parent = parent.parent)
2184          {
2185             if(!parent.header)
2186             {
2187                if(style.treeBranch)
2188                   indent += 20;
2189                else
2190                   indent += 15;
2191             }
2192          }
2193          if(style.rootCollapse) indent += 20;
2194          x += indent;
2195
2196          dataDisplayFlags.fullRow = style.fullRowSelect;
2197          dataDisplayFlags.active = isActive;
2198          dataDisplayFlags.header = row.header;
2199
2200          surface.Clip(null);
2201          if(style.collapse)
2202          {
2203             collapseRowStart = rowStart;
2204
2205             if(!(style.treeBranch))
2206             {
2207                x += 15;
2208                rowStart += 15;
2209             }
2210          }
2211
2212          if(style.multiSelect)
2213          {
2214             dataDisplayFlags.selected = row.selectedFlag == selected || row.selectedFlag == tempSelected;
2215             dataDisplayFlags.current = row == currentRow || (!currentRow && row == firstRowShown);
2216          }
2217          else
2218          {
2219             dataDisplayFlags.selected = row.selectedFlag == selected || row.selectedFlag == tempSelected;
2220             dataDisplayFlags.current = row == currentRow || (!currentRow && row == firstRowShown);
2221             /*
2222             if(row == currentRow)
2223             {
2224                dataDisplayFlags.current = true;
2225                dataDisplayFlags.selectedFlag = true;
2226             }
2227             else if(!currentRow && row == firstRowShown)
2228             {
2229                dataDisplayFlags.current = true;
2230             }*/
2231          }
2232
2233          surface.TextOpacity(true);
2234
2235          background = this.background;
2236          foreground = this.foreground;
2237
2238          // Draw the current row background
2239          if(row.header)
2240          {
2241             background = activeBorder;
2242             surface.SetBackground(activeBorder);
2243             surface.Area(rowStart, y, clientSize.w, (y + rowHeight) - 1);
2244             foreground = branchesColor;
2245          }
2246          else if(dataDisplayFlags.selected)
2247          {
2248             if(dataDisplayFlags.selected && (isActive || style.alwaysHL || (style.alwaysEdit && style.fullRowSelect)))
2249             {
2250                if(!isActive && style.alwaysEdit)
2251                   background = activeBorder;
2252                else
2253                   background = selectionColor ? selectionColor : SELECTION_COLOR;
2254                if(style.fullRowSelect)
2255                {
2256                   int offset = (style.alwaysEdit) ? 2 : 1;
2257                   surface.SetBackground(background);
2258                   surface.Area(rowStart, y, clientSize.w, (y + rowHeight) - offset);
2259                }
2260                if(isActive || !(style.alwaysEdit))
2261                   foreground = selectionText ? selectionText : SELECTION_TEXT;
2262                else
2263                   foreground = branchesColor;
2264             }
2265          }
2266
2267          if(icon)
2268          {
2269             surface.Blit(icon, x + (20 - icon.width) /2,y + 2,0,0, icon.width, icon.height);
2270             x += 20;
2271          }
2272
2273          if(row.noneRow)
2274          {
2275             int width = clientSize.w;
2276             Box clip;
2277             dataDisplayFlags.firstField = true;
2278             clip.left = x - EXTRA_SPACE / 2+1;
2279             clip.top = y;
2280             clip.right = x + width - EXTRA_SPACE/2 - 0;
2281             clip.bottom = y + rowHeight - 1;
2282             surface.Clip(&clip);
2283
2284             surface.TextFont(font);
2285
2286             surface.SetForeground(foreground);
2287             surface.SetBackground(background);
2288
2289             class(String)._vTbl[__ecereVMethodID_class_OnDisplay](class(String), "(none)", surface, x, y - 1 + (rowHeight - fontH)/2, width - EXTRA_SPACE/2, null, Alignment::left, dataDisplayFlags);
2290          }
2291          else
2292          {
2293             // Draw the rows
2294             for(field = fields.first; field; field = field.next)
2295             {
2296                uint index;
2297                int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
2298                   clientSize.w - field.x : (field.width + EXTRA_SPACE);
2299
2300                // Box clip = { x, y+1, x + field.width - EXTRA_SPACE - 1, y + rowHeight - 2 };
2301                Box clip;
2302
2303                //width -= EXTRA_SPACE;
2304
2305                if(!field.prev) width -= indent;
2306
2307
2308                dataDisplayFlags.firstField = field.prev ? false : true;
2309
2310                if(!dataDisplayFlags.firstField && !dataDisplayFlags.fullRow)
2311                {
2312                   background = this.background;
2313                   foreground = this.foreground;
2314                }
2315
2316                if(!isActive && dataDisplayFlags.selected && style.alwaysEdit && field.editable)
2317                {
2318                   surface.Clip(null);
2319                   surface.SetBackground(background);
2320                   surface.Area(x-3, y, x+width-1, y + rowHeight-2);
2321                }
2322
2323                clip.left = x - EXTRA_SPACE / 2+1;
2324                clip.top = y;
2325                clip.right = x + width - EXTRA_SPACE/2 - 0;
2326                clip.bottom = y + rowHeight - 1;
2327                surface.Clip(&clip);
2328
2329                for(index = 0, cell = row.cells.first; cell && index != field.index; index++, cell = cell.next);
2330                // Should always be as many cells in the row as fields in the listbox
2331                if(cell && cell.isSet && field.dataType)
2332                {
2333                   if(row.header)
2334                      surface.TextFont(boldFont);
2335                   else
2336                      surface.TextFont(font);
2337
2338                   surface.SetForeground(foreground);
2339                   surface.SetBackground(background);
2340
2341                   if(field.dataType.type == noHeadClass || field.dataType.type == normalClass)
2342                      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);
2343                   else
2344                      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);
2345                }
2346
2347                if(!isActive && dataDisplayFlags.selected && style.alwaysEdit && field.editable)
2348                   background = activeBorder;
2349
2350                if(!dataDisplayFlags.firstField && !dataDisplayFlags.fullRow)
2351                {
2352                   background = activeBorder;
2353                   foreground = this.background;
2354                }
2355
2356                x += width;// + EXTRA_SPACE;
2357
2358                if(row.header) break;
2359             }
2360          }
2361
2362          if(style.collapse)
2363          {
2364             int plusIndent = (style.treeBranch) ? (indent - 20 + 4) : indent;
2365             surface.Clip(null);
2366             if(row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)))
2367             {
2368                surface.SetForeground(row.header ? headerCollapseForeground : this.foreground);
2369                surface.Rectangle(collapseRowStart + 3 + plusIndent, y + PLUSY, collapseRowStart + 11 + plusIndent, y + PLUSY + 8);
2370
2371                surface.SetBackground(row.header ? (activeBorder) : (this.background)); //white
2372                surface.Area(collapseRowStart + 4 + plusIndent, y + PLUSY + 1, collapseRowStart + 10 + plusIndent, y + PLUSY + 7);
2373
2374                surface.HLine(collapseRowStart + 5 + plusIndent, collapseRowStart + 9 + plusIndent, y+PLUSY+4);
2375                if(row.collapsed)
2376                   surface.VLine(y + PLUSY + 2, y + PLUSY + 6, collapseRowStart + 7 + plusIndent);
2377             }
2378
2379          }
2380
2381          // Draw the current row stipple
2382          if(style.fullRowSelect && !(style.alwaysEdit) && (dataDisplayFlags.current) && isActive)
2383          {
2384             surface.Clip(null);
2385             if(isActive)
2386             {
2387                surface.LineStipple(0x5555);
2388                if(dataDisplayFlags.selected)
2389                   surface.SetForeground(stippleColor);
2390                else
2391                   surface.SetForeground(this.foreground);
2392             }
2393             else
2394                surface.SetForeground(selectionColor ? selectionColor : SELECTION_COLOR);
2395             surface.Rectangle(0, y, clientSize.w-1, (y + rowHeight) - 1);
2396             surface.LineStipple(0);
2397          }
2398
2399          y += rowHeight;
2400          if(y >= clientSize.h)
2401             break;
2402       }
2403       if(firstRowShown) surface.Clip(null);
2404       if(this.dragRow && this.dropIndex != -1)
2405       {
2406          int dropIndex = this.dropIndex;
2407          int y;
2408
2409          if(!style.multiSelect && currentRow.index < this.dropIndex)
2410             dropIndex++;
2411          surface.DrawingChar(223);
2412
2413          y = style.header ? rowHeight : 0;
2414          y += dropIndex * rowHeight - scroll.y;
2415
2416          surface.SetForeground(Color { 85, 85, 255 });
2417          surface.HLine(0, clientSize.w-1, y);
2418          surface.HLine(0, clientSize.w-1, y + 1);
2419       }
2420    }
2421
2422    void OnDrawOverChildren(Surface surface)
2423    {
2424       if(draggingField && this.dropField)
2425       {
2426          int position = this.dropField.x;
2427          if(draggingField.x < position)
2428             position += this.dropField.width + EXTRA_SPACE;
2429
2430          surface.SetForeground(Color { 85, 85, 255 });
2431          surface.VLine(0, rowHeight - 1, position - scroll.x - 2);
2432          surface.VLine(0, rowHeight - 1, position - scroll.x);
2433       }
2434       if(sortField && !style.clearHeader && style.header)
2435       {
2436          DataField field = sortField;
2437          int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
2438             clientSize.w - field.x : (field.width + EXTRA_SPACE);
2439          int tw = 0, th = 0;
2440          if(field.header)
2441             surface.TextExtent(field.header, strlen(field.header), &tw, &th);
2442          if(tw < width - EXTRA_SPACE)
2443          {
2444             bool up = field.sortOrder == 1;
2445             int x = 4, y = 4;
2446             Box clip = 
2447             { 
2448                field.x + 2 - scroll.x, 0, 
2449                field.x + width + EXTRA_SPACE - 1 - scroll.x, rowHeight
2450             };
2451             surface.Clip(&clip);
2452             if(field.alignment == left || field.alignment == center)
2453             {
2454                if(field.alignment == center)
2455                   x = field.x + (width + EXTRA_SPACE - tw) / 2 + tw + EXTRA_SPACE + 4;
2456                else
2457                   x = field.x + tw + EXTRA_SPACE + 4;
2458              
2459                x = Min(x, field.x + width - 4);
2460             }
2461             else if(field.alignment == right)
2462             {
2463                x = field.x + width - tw - EXTRA_SPACE - 4;
2464                x = Max(x, field.x + 2);
2465             }
2466             x -= scroll.x;
2467
2468             if(guiApp.textMode)
2469             {
2470                // surface.SetForeground((wmenu.selectedFlag == item) ? white : black);
2471                // surface.WriteText(clientSize.w-8, y+(wmenu.rh - 8)/2, "\020", 1);
2472             }
2473             else
2474             {
2475                if(up)
2476                {
2477                   surface.SetForeground(Color { 128,128,128 } );
2478                   surface.DrawLine(x + 3, y, x, y + 5);
2479                   surface.PutPixel(x + 1, y + 5);
2480                   surface.PutPixel(x + 1, y + 3);
2481                   surface.PutPixel(x + 2, y + 1);
2482             
2483                   surface.SetForeground(white);
2484                   surface.DrawLine(x + 4, y, x + 7, y + 5);
2485                   surface.PutPixel(x + 6, y + 5);
2486                   surface.PutPixel(x + 6, y + 3);
2487                   surface.PutPixel(x + 5, y + 1);
2488
2489                   surface.DrawLine(x, y + 6, x + 7, y + 6);
2490                }
2491                else
2492                {
2493                   surface.SetForeground(Color { 128,128,128 });
2494                   surface.DrawLine(x + 3, y+6, x, y+1);
2495                   surface.PutPixel(x + 1, y+1);
2496                   surface.PutPixel(x + 1, y+3);
2497                   surface.PutPixel(x + 2, y+5);
2498             
2499                   surface.SetForeground(white);
2500                   surface.DrawLine(x + 4, y+6, x + 7, y+1);
2501                   surface.PutPixel(x + 6, y+1);
2502                   surface.PutPixel(x + 6, y+3);
2503                   surface.PutPixel(x + 5, y+5);
2504
2505                   surface.DrawLine(x, y, x + 7, y);
2506                }
2507             }
2508             surface.Clip(null);
2509          }
2510       }
2511
2512    }
2513
2514    void OnResize(int w, int h)
2515    {
2516       DataField field;
2517       bool showEndBevel = false;
2518       int x = 0;
2519       if(style.collapse && !style.treeBranch)
2520          x += 15;
2521       for(field = fields.first; field; field = field.next)
2522       {
2523          int width = field.width + EXTRA_SPACE;
2524          field.x = x;
2525          x += width;
2526       }
2527       width = x;
2528
2529       SetScrollArea(
2530          width,
2531          (rowCount * rowHeight) + 
2532          ((style.header) ? rowHeight : 0) -
2533          ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
2534
2535       for(field = fields.first; field; field = field.next)
2536       {
2537          int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
2538             clientSize.w - field.x : (field.width + EXTRA_SPACE);
2539          if(style.header && field.headButton)
2540          {
2541             showEndBevel = true;
2542             if(width > 0)
2543             {
2544                field.headButton.position = { field.x, 0 };
2545                field.headButton.size = { width, rowHeight };
2546                field.headButton.visible = true;
2547             }
2548             else
2549                field.headButton.visible = false;
2550          }
2551       }
2552
2553       if(!style.fillLastField && showEndBevel && endBevel)
2554       {
2555          endBevel.position = { x, 0 };
2556          endBevel.size = { clientSize.w + 2 - x, rowHeight };
2557          endBevel.visible = true;
2558       }
2559       else if(endBevel)
2560          endBevel.visible = false;
2561
2562       if(style.alwaysEdit && editData && editData.visible)
2563       {
2564          HideEditBox(true, false, true);
2565       }
2566    }
2567
2568    void AdaptToFieldWidth(DataField field, bool doScroll)
2569    {
2570       OnResize(clientSize.w, clientSize.h);
2571
2572       // Scroll appropriately
2573       if(doScroll)
2574       {
2575          if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x &&
2576                  field.x >= field.x + field.width + EXTRA_SPACE - clientSize.w)
2577          {
2578             SetScrollPosition(field.x + field.width + EXTRA_SPACE - clientSize.w, scroll.y);
2579          }
2580          else if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x ||
2581                  field.x < scroll.x)
2582             SetScrollPosition(field.x, scroll.y);
2583       }
2584       Update(null);
2585    }
2586
2587    bool HeaderPushed(Button control, int x, int y, Modifiers mods)
2588    {
2589       DataField field = (DataField)control.id;
2590       // false: dont destroy edit box
2591       HideEditBox(true, false, true);
2592       if(style.resizable && ((!field && x < RESIZE_BORDER && fields.last) ||
2593          (field && x < RESIZE_BORDER && field.prev) || 
2594          (field && x >= control.clientSize.w - RESIZE_BORDER)))
2595       {
2596          if(!field)
2597             field = fields.last;
2598          else if(x < RESIZE_BORDER && field.prev)
2599             field = field.prev;
2600
2601          resizingField = field;
2602          this.resizeX = x + control.position.x;
2603          this.startWidth = field.width;
2604          this.oldX = x - scroll.x;
2605          return false;
2606       }
2607       else if(field)
2608       {
2609          draggingField = field;
2610          if(style.moveFields)
2611             field.headButton.stayDown = true;
2612          else if(!style.sortable)
2613             return false;
2614       }
2615       else
2616          return false;
2617       return true;
2618    }
2619
2620    bool HeaderMouseMove(Button control, int x, int y, Modifiers mods)
2621    {
2622       if(resizingField)
2623       {
2624          // Resize left
2625          DataField field = resizingField;
2626
2627          x += control.position.x;
2628
2629          // Tweak to prevent shrinking field if we're actually moving right
2630          if(x - scroll.x > this.oldX && 
2631             this.startWidth + x - this.resizeX < field.width)
2632          {
2633             this.oldX = x - scroll.x;
2634             return true;
2635          }
2636          this.oldX = x - scroll.x;
2637
2638          field.width = this.startWidth + x - this.resizeX;
2639          field.width = Max(field.width, - EXTRA_SPACE);
2640
2641          AdaptToFieldWidth(field, true);
2642       }
2643       else if(draggingField)
2644       {
2645          x += control.position.x;
2646          if(style.moveFields)
2647          {
2648             DataField field = fields.last;
2649             int fieldX = 0;
2650             for(field = fields.first; field; field = field.next)
2651             {
2652                fieldX += ((field.width || style.resizable) ? 
2653                   field.width : clientSize.w) + EXTRA_SPACE;
2654                if(fieldX > x) 
2655                   break;
2656             }
2657             if(draggingField == field)
2658             {
2659                // Reset scroll position
2660                if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x &&
2661                        field.x >= field.x + field.width + EXTRA_SPACE - clientSize.w)
2662                {
2663                   SetScrollPosition(
2664                      field.x + field.width + EXTRA_SPACE - clientSize.w, 
2665                      scroll.y);
2666                }
2667                else if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x ||
2668                        field.x < scroll.x)
2669                   SetScrollPosition(field.x, scroll.y);
2670                field = null;
2671             }
2672             if(this.dropField != field)
2673             {
2674                this.dropField = field;
2675                if(field)
2676                {
2677                   int position = field.x;
2678                   // Moving right
2679                   if(draggingField.x < position)
2680                   {
2681                      position += field.width + EXTRA_SPACE - clientSize.w;
2682                      if(position > scroll.x)
2683                         SetScrollPosition(position, scroll.y);
2684                   }
2685                   // Moving Left
2686                   else
2687                   {
2688                      if(position < scroll.x)
2689                         SetScrollPosition(position, scroll.y);
2690                   }
2691
2692                   this.movingFields = true;
2693                }
2694                Update(null);
2695             }
2696          }
2697       }
2698       else if(style.resizable)
2699       {
2700          DataField field = (DataField)control.id;
2701          if(field)
2702          {
2703             if(x < RESIZE_BORDER && field.prev)
2704                control.cursor = guiApp.GetCursor(sizeWE);
2705             else if(x >= control.clientSize.w - RESIZE_BORDER)
2706                control.cursor = guiApp.GetCursor(sizeWE);
2707             else
2708                control.cursor = null;
2709          }
2710          else
2711          {
2712             if(x < RESIZE_BORDER && fields.last)
2713                control.cursor = guiApp.GetCursor(sizeWE);
2714             else
2715                control.cursor = null;
2716          }
2717       }
2718       return true;
2719    }
2720
2721    bool HeaderReleased(Button control, int x, int y, Modifiers mods)
2722    {
2723       if(resizingField)
2724       {
2725          NotifyResized(master, this, resizingField, mods);
2726          resizingField = null;
2727       }
2728
2729       if(draggingField)
2730       {
2731          bool result = true;
2732          
2733          if(style.moveFields)
2734          {
2735             if(dropField)
2736             {
2737                // Find which field
2738                DataField switchField = fields.last;
2739                DataField field;
2740                int fieldX = 0;
2741
2742                x += draggingField.x;
2743                for(field = fields.first; field; field = field.next)
2744                {
2745                   fieldX += ((field.width || style.resizable) ? 
2746                      field.width : clientSize.w) + EXTRA_SPACE;
2747                   if(fieldX > x) 
2748                   {
2749                      switchField = field;
2750                      break;
2751                   }
2752                }
2753                if(switchField && draggingField != switchField && this.dropField)
2754                {
2755                   for(field = fields.first; field; field = field.next)
2756                   {
2757                      if(field == switchField || field == draggingField)
2758                         break;
2759                   }
2760
2761                   // Switch field first: move before
2762                   if(field == switchField)
2763                      draggingField.Move(switchField.prev);
2764                   // Dragged field first: move after
2765                   else
2766                      draggingField.Move(switchField);
2767
2768                   NotifyMovedField(master, this, draggingField, mods);
2769                }
2770                draggingField.headButton.stayDown = false;
2771             }
2772             if(movingFields)
2773                result = false;
2774             dropField = null;
2775             movingFields = false;
2776          }
2777          draggingField = null;
2778          return result;
2779       }
2780       return true;
2781    }
2782
2783    bool HeaderClicked(Button control, int x, int y, Modifiers mods)
2784    {
2785       if(style.header && !this.dropField && style.sortable)
2786       {
2787          DataField field = (DataField)control.id;
2788          if(sortField == field)
2789             field.sortOrder *= -1;
2790          else
2791             sortField = field;
2792          if(field)
2793          {
2794             Sort(sortField, field.sortOrder);
2795             NotifySort(master, this, field, mods);
2796          }
2797       }
2798       return true;
2799    }
2800
2801    watch(visible)
2802    {
2803       if(style.freeSelect)
2804       {
2805          if(!visible)
2806          {
2807             ReleaseCapture();
2808             this.rolledOver = this.dragging = false;
2809          }
2810          /*else
2811             Capture();*/
2812       }
2813    };
2814
2815    bool OnLoadGraphics()
2816    {
2817       display.FontExtent(fontObject, "W", 1, null, &fontH); 
2818       if(!style.heightSet)
2819       {
2820          rowHeight = Max(fontH + 2, 16) + (style.alwaysEdit ? 1 : 0);
2821          SetScrollLineStep(8, rowHeight);
2822       }
2823       return true;
2824    }
2825
2826    void OnApplyGraphics()
2827    {
2828       SetScrollLineStep(8, rowHeight);
2829       if(style.header)
2830       {
2831          DataField field;
2832          for(field = fields.first; field; field = field.next)
2833          {
2834             if(field.headButton)
2835             {
2836                field.headButton.bevel = (!guiApp.textMode && !style.clearHeader);
2837                if(guiApp.textMode)
2838                   field.headButton.background = Color { 0, 170, 0 };
2839             }
2840          }
2841       }
2842       OnResize(clientSize.w, clientSize.h);
2843    }
2844
2845    bool OnResizing(int *w, int *h)
2846    {
2847       if(rows.first)
2848       {
2849          if(!initSize.w && (!anchor.left.type || !anchor.right.type) /**w*/)
2850          {
2851             // Use widest item
2852             DataRow row;
2853             int maxWidth = 0;
2854             Font font = fontObject;
2855             Font boldFont = this.boldFont.font;
2856             Display display = this.display;
2857             
2858             for(row = rows.first; row; row = row.GetNextRow())
2859             {
2860                Bitmap icon = row.icon ? row.icon.bitmap : null;
2861                int x = -scroll.x + EXTRA_SPACE / 2-1;
2862                DataField field;
2863                int indent = 0;
2864                DataRow parent;
2865                for(parent = row.parent; parent; parent = parent.parent)
2866                {
2867                   if(!parent.header)
2868                   {
2869                      if(style.treeBranch)
2870                         indent += 20;
2871                      else
2872                         indent += 15;
2873                   }
2874                }
2875                if(style.rootCollapse) indent += 20;
2876                x += indent;
2877                if(style.collapse && !(style.treeBranch)) x += 15;
2878                if(icon)
2879                   x += 20;
2880
2881                // Compute the rows size
2882                for(field = fields.first; field; field = field.next)
2883                {
2884                   if(((style.resizable && (!(style.alwaysEdit) || field.next)) || field.width) && !row.header)
2885                      x += field.width - (field.prev ? 0 : indent);
2886                   else
2887                   {
2888                      ListBoxCell cell;
2889                      uint index;
2890                      for(index = 0, cell = row.cells.first; index != field.index; index++, cell = cell.next);
2891
2892                      // Should always be as many cells in the row as fields in the listbox
2893                      if(cell && cell.isSet && field.dataType)
2894                      {
2895                         Bitmap icon = null;
2896                         char tempString[1024];
2897                         char * string;
2898                         int tw, th;
2899                         if(field.dataType.type == 0 normalClass || field.dataType.type == noHeadClass)
2900                            string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, cell.data[0], tempString, field.userData, null);
2901                         else
2902                            string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, cell.data, tempString, field.userData, null);
2903                         /* GCC-4.4 Bug!
2904                         if(!string) string = "";
2905                         display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, &th);
2906                         */
2907                         if(string)
2908                            display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, &th);
2909                         else
2910                            display.FontExtent(row.header ? boldFont : font, "", 0, &tw, &th);
2911                         x += tw;
2912                      }
2913                      if(row.header) break;
2914                   }
2915                   x += EXTRA_SPACE;
2916                }
2917                maxWidth = Max(maxWidth, x);
2918             }
2919             *w = maxWidth;
2920          }
2921          if(!*h)
2922          {
2923             *h = Min(this.maxShown, this.rowCount) * rowHeight;
2924          }
2925       }
2926       else
2927       {
2928          if(!*w) *w = rowHeight * 5;
2929          if(!*h) *h = rowHeight * 5;
2930       }
2931       return true;
2932    }
2933
2934    watch(font)
2935    {
2936       FontResource font = this.font;
2937       FontResource boldFont
2938       {
2939          faceName = font.faceName, size = font.size, bold = true
2940       };
2941       AddResource(boldFont);
2942       RemoveResource(this.boldFont);
2943       this.boldFont = boldFont;
2944
2945       OnLoadGraphics();
2946
2947       SetInitSize(initSize);
2948    };
2949
2950    bool OnMouseMove(int x, int y, Modifiers mods)
2951    {
2952       bool isTimer = false;
2953       int realX = x, realY = y;
2954
2955       if(insideNotifySelect) return true;
2956
2957       if(style.alwaysEdit && style.resizable &&
2958          resizingField && !(mods.isSideEffect))
2959       {
2960         // Resize left
2961          DataField field = resizingField;
2962          field.width = this.startWidth + x - this.resizeX;
2963          field.width = Max(field.width, - EXTRA_SPACE);
2964
2965          AdaptToFieldWidth(field, true);
2966       }
2967
2968       cursor = null;
2969       if(style.alwaysEdit && style.resizable)
2970       {
2971          int vx = -scroll.x - 1;
2972          DataField field;
2973
2974          if(style.collapse && !(style.treeBranch))
2975             vx += 15;
2976
2977          for(field = fields.first; field; field = field.next)
2978          {
2979             int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
2980                clientSize.w - field.x : (field.width + EXTRA_SPACE);
2981
2982             if(field.prev)
2983             {
2984                if(Abs(x - vx) < 2)
2985                {
2986                   cursor = guiApp.GetCursor(sizeWE);
2987                   break;
2988                }
2989             }
2990             vx += width + EXTRA_SPACE;
2991          }
2992       }
2993
2994       if((editData && editData.visible) || (style.alwaysEdit))
2995          return true;
2996       
2997       if(x == MAXINT && y == MAXINT)
2998       {
2999          x = this.mouseX;
3000          y = this.mouseY;
3001          isTimer = true;
3002       }
3003
3004       // ADDED THIS CHECK FOR FieldDropBox LEAKS
3005       if(/*!mods.isSideEffect && */(this.rolledOver || !this.dragging))
3006       {
3007          int rowY = (style.header) ? rowHeight : 0;
3008          DataRow row = null;
3009          int rowIndex;
3010
3011          mouseX = x;
3012          mouseY = y;
3013
3014          if(this.dragging &&
3015             ((vertScroll && vertScroll.visible && 
3016              (y < 0 || y >= clientSize.h)) ||
3017              (horzScroll && horzScroll.visible && 
3018              (x < 0 || x >= clientSize.w))))
3019          {
3020             timer.Start();
3021             if(isTimer)
3022             {
3023                if(vertScroll && vertScroll.visible && 
3024                   (y < 0 || y >= clientSize.h))
3025                   vertScroll.Action((y<0)?up:down, 0, 0);
3026                if(horzScroll && horzScroll.visible && 
3027                   (x < 0 || x >= clientSize.w))
3028                   horzScroll.Action((x<0)?up:down, 0, 0);
3029             }
3030          }
3031          else
3032             timer.Stop();
3033
3034          // This must be done after the scrolling took place
3035          rowIndex = firstRowShown ? firstRowShown.index : -1;
3036          y = Max(y, 0);
3037          y = Min(y, clientSize.h-1);
3038          for(row = firstRowShown; row; row = row.GetNextRow(), rowIndex ++)
3039          {
3040             rowY += rowHeight;
3041             if(rowY > y)
3042             {
3043                break;
3044             }
3045          }
3046
3047          if(row && currentRow != row)
3048          {
3049             if(this.dragRow && style.moveRows)
3050             {
3051                if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
3052                   rowIndex = -1;
3053                else if(style.multiSelect)
3054                {
3055                   DataRow thisRow;
3056                   for(thisRow = rows.first; thisRow; thisRow = thisRow.GetNextRow())
3057                      if((thisRow.selectedFlag == selected || thisRow.selectedFlag == tempSelected) || 
3058                         thisRow == row)
3059                         break;
3060                   if(thisRow != row)
3061                      rowIndex++;
3062                }
3063                if(this.dropIndex != rowIndex)
3064                {
3065                   this.dropIndex = rowIndex;
3066                   this.editRow = null;
3067                   Update(null);
3068                   this.movedRow = true;
3069                }
3070             }
3071             else if((style.freeSelect  || this.dragging) && ((realX>= 0 && realY >= 0 && realX< clientSize.w && realY < clientSize.h) || this.rolledOver))
3072             {
3073                if(!(style.multiSelect))
3074                {
3075                   if(currentRow)currentRow.selectedFlag = unselected;
3076                   if(row)row.selectedFlag = selected;
3077                }
3078                currentRow = row;
3079
3080                if(style.multiSelect)
3081                {
3082                   DataRow selRow;
3083
3084                   for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3085                   {
3086                      if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3087                      else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3088                   }
3089
3090                   if(rowIndex >= clickedRow.index)
3091                   {
3092                      for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
3093                      {
3094                         selRow.selectedFlag = (selRow.selectedFlag == selected) ? tempUnselected : tempSelected;
3095                         if(selRow == row)
3096                            break;
3097                      }
3098                   }
3099                   else
3100                   {
3101                      for(selRow = row; selRow; selRow = selRow.GetNextRow())
3102                      {
3103                         selRow.selectedFlag = (selRow.selectedFlag == selected) ? tempUnselected : tempSelected;
3104                         if(selRow == clickedRow)
3105                            break;
3106                      }
3107                   }
3108                }
3109                Update(null);
3110                if(style.freeSelect)
3111                   NotifyHighlight(master, this, currentRow, mods);
3112                else
3113                {
3114                   insideNotifySelect = true;
3115                   NotifySelect(master, this, currentRow, mods);
3116                   insideNotifySelect = false;
3117                }
3118
3119                if(style.alwaysEdit && currentRow)
3120                   currentRow.Edit(currentField);
3121             }
3122          }
3123       }
3124       return true;
3125    }
3126
3127    bool OnMouseOver(int x, int y, Modifiers mods)
3128    {
3129       if(this.dragging)
3130          this.rolledOver = true;
3131       return true;
3132    }
3133
3134    bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
3135    {
3136       // TOCHECK: WAS THIS MISSING ? CHECK FOR SLOWDOWN
3137       if(!active) Update(null);
3138
3139       if(!active && (!swap || !swap.isModal))
3140       {
3141          // true: destroy edit box
3142          HideEditBox(true, true, false);
3143       }
3144       else if(!swap || !swap.isModal)
3145       {
3146          // Bring back edit box
3147          if(currentRow && style.alwaysEdit)
3148          {
3149             currentRow.Edit(currentField ? currentField : null);
3150          }
3151          Update(null);
3152       }
3153       return true; //NotifyActivate(master, this, active, swap, 0);
3154    }
3155
3156
3157    bool OnButtonDown(int x, int y, Modifiers mods, bool right)
3158    {
3159       bool result = true;
3160       // Check to see if we're dragging the vertical divider
3161       if(style.alwaysEdit && style.resizable && !right)
3162       {
3163          int vx = -scroll.x - 1;// + EXTRA_SPACE;// / 2 - 1;
3164          DataField field;
3165
3166          if(style.collapse && !(style.treeBranch))
3167             vx += 15;
3168
3169          for(field = fields.first; field; field = field.next)
3170          {
3171             int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
3172                clientSize.w - field.x : (field.width + EXTRA_SPACE);
3173
3174             if(field.prev)
3175             {
3176                if(Abs(x - vx) < 2)
3177                {
3178                   resizingField = field.prev;
3179                   this.resizeX = x;
3180                   this.startWidth = resizingField.width;
3181                   Capture();
3182                   SetMouseRangeToClient();
3183                   break;
3184                }
3185             }
3186             vx += width + EXTRA_SPACE;
3187          }
3188       }
3189
3190       if(!(style.freeSelect))
3191       {
3192          int rowY = (style.header) ? rowHeight : 0;
3193          DataRow row = null;
3194          int rowIndex = firstRowShown ? firstRowShown.index : -1;
3195          DataRow previousRow = currentRow;
3196          DataRow newCurrentRow = null;
3197          DataField newCurrentField = null;
3198          bool moveMultiple = false;
3199          int numSelected = 0;
3200          int rowStart = -scroll.x;
3201
3202          if(style.multiSelect)
3203          {
3204             if(!right)
3205             {
3206                DataRow row;
3207                if(!(mods.shift))
3208                {
3209                   for(row = rows.first; row; row = row.GetNextRow())
3210                   {
3211                      if(row.selectedFlag == tempSelected)
3212                         row.selectedFlag = selected;
3213                      else if(row.selectedFlag == tempUnselected)
3214                         row.selectedFlag = unselected;
3215                      if(row.selectedFlag == selected)
3216                         numSelected++;
3217                   }
3218                }
3219             }
3220          }
3221
3222          for(row = firstRowShown; row; row = row.GetNextRow(), rowIndex ++)
3223          {
3224             rowY += rowHeight;
3225             if(rowY > y || (style.multiSelect && !row.GetNextRow())) 
3226             {
3227                int plusIndent = 0;
3228                if(style.treeBranch)
3229                {
3230                   DataRow parent;
3231                   for(parent = (style.rootCollapse) ? row.parent : (row.parent ? row.parent.parent : null); parent; parent = parent.parent)
3232                      if(!parent.header)
3233                         plusIndent += 20;
3234                   plusIndent += 4;
3235                }
3236
3237                /*    THIS WAS TOO STRICT:
3238                if(style.collapse && row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)) &&
3239                   (x >= rowStart + 3 + plusIndent && y >= rowY - rowHeight + PLUSY && x <= rowStart + 11 + plusIndent && y <= rowY - rowHeight + PLUSY + 8))
3240                */
3241                if(style.collapse && 
3242                   (x >= rowStart && y >= rowY - rowHeight && x <= rowStart + 18 + plusIndent && y <= rowY + rowHeight-1))
3243                {
3244                   if(row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)) && x >= plusIndent)
3245                      row.collapsed = !row.collapsed;
3246                   return false;
3247                }
3248                else
3249                {
3250                   if(rowY > y)
3251                   {
3252                      newCurrentRow = row;
3253                   }
3254                   if(style.multiSelect)
3255                   {
3256                      // Deselect everything if user didn't clicked on a row
3257                      if(y >= rowY)
3258                      {
3259                         DataRow selRow;
3260                         for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3261                            selRow.selectedFlag = unselected;
3262                         clickedRow = row;
3263                         //this.clickedRowIndex = rowIndex;
3264                      }
3265                      else if(style.moveRows && !(mods.shift) && 
3266                         (row.selectedFlag == selected || row.selectedFlag == tempSelected) &&
3267                         !right && !(mods.isActivate))
3268                         moveMultiple = true;
3269                      else
3270                      {
3271                         DataRow selRow;
3272                         if(right)
3273                         {
3274                            if(row.selectedFlag == tempUnselected || row.selectedFlag == unselected)
3275                            {
3276                               for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3277                                  selRow.selectedFlag = unselected;
3278                               row.selectedFlag = selected;
3279                            }
3280                            clickedRow = row;
3281                            //this.clickedRowIndex = rowIndex;
3282                         }
3283                         else
3284                         {
3285                            if(!(mods.ctrl))
3286                            {
3287                               for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3288                                  selRow.selectedFlag = unselected;
3289                            }
3290                            else
3291                            {
3292                               for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3293                               {
3294                                  if(selRow != clickedRow)
3295                                  {
3296                                     if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3297                                     else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3298                                  }
3299                               }
3300                            }
3301
3302                            if(mods.shift)
3303                            {
3304                               if(rowIndex >= clickedRow.index)
3305                               {
3306                                  for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
3307                                  {
3308                                     if(mods.ctrl)
3309                                     {
3310                                        if(selRow != clickedRow)
3311                                        {
3312                                           if(selRow.selectedFlag) 
3313                                              selRow.selectedFlag = tempUnselected;
3314                                           else
3315                                              selRow.selectedFlag = tempSelected;
3316                                        }
3317                                     }
3318                                     else
3319                                        selRow.selectedFlag = selected;
3320                                     if(selRow == row)
3321                                        break;
3322                                  }
3323                               }
3324                               else
3325                               {
3326                                  for(selRow = row; selRow; selRow = selRow.GetNextRow())
3327                                  {
3328                                     if(mods.ctrl)
3329                                     {
3330                                        if(selRow != clickedRow)
3331                                        {
3332                                           if(selRow.selectedFlag)
3333                                              selRow.selectedFlag = tempUnselected;
3334                                           else
3335                                              selRow.selectedFlag = tempSelected;
3336                                        }
3337                                     }
3338                                     else
3339                                        selRow.selectedFlag = selected;
3340                                     if(selRow == clickedRow)
3341                                        break;
3342                                  }
3343                               }
3344                            }
3345                            else
3346                            {
3347                               if(mods.ctrl)
3348                               {
3349                                  if(row.selectedFlag)
3350                                     row.selectedFlag = tempUnselected;
3351                                  else row.selectedFlag = tempSelected;
3352                               }
3353                               else
3354                                  row.selectedFlag = tempSelected;
3355                               clickedRow = row;
3356                               //this.clickedRowIndex = rowIndex;
3357                            }
3358                         }
3359                      }
3360                   }
3361                }
3362                break;
3363             }
3364          }
3365
3366          // true: destroy edit box
3367          if(newCurrentRow)
3368          {
3369             incref newCurrentRow;
3370          }
3371
3372          if(currentRow != newCurrentRow)
3373             HideEditBox(true, true, false);
3374
3375          if(newCurrentRow)
3376          {
3377             if(newCurrentRow._refCount <= 1)
3378                delete newCurrentRow;
3379             else
3380                newCurrentRow._refCount--;
3381          }
3382
3383          if(newCurrentRow)
3384          {
3385             if(!(style.multiSelect))
3386             {
3387                if(currentRow) currentRow.selectedFlag = unselected;
3388                if(newCurrentRow) newCurrentRow.selectedFlag = selected;
3389             }
3390          }
3391
3392          if(currentRow != newCurrentRow)
3393          {
3394             /*
3395             // true: destroy edit box
3396             if(newCurrentRow)
3397             {
3398                //incref newCurrentRow;
3399                incref newCurrentRow;
3400             }
3401
3402             HideEditBox(true, true, false);
3403             */
3404
3405             if(newCurrentRow)
3406             {
3407                int headerSize = ((style.header) ? rowHeight : 0);
3408                int height = clientSize.h + 1 - headerSize;
3409
3410                /*if(newCurrentRow._refCount <= 1)
3411                   delete newCurrentRow;
3412                else
3413                {
3414                   newCurrentRow._refCount--;
3415                   //newCurrentRow._refCount--;
3416                }
3417                */
3418                currentRow = newCurrentRow;
3419
3420                if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
3421                   SetScrollPosition(scroll.x,
3422                      currentRow.index * rowHeight - height + rowHeight);
3423                else if(!currentRow || currentRow.index * rowHeight < scroll.y)
3424                {
3425                   int line = currentRow ? currentRow.index * rowHeight : 0;
3426                   //SNAPUP(line, rowHeight);
3427                   SetScrollPosition(scroll.x, line);
3428                }
3429
3430                // GO THROUGH SetCurrentRow eventually?
3431                // SetCurrentRow(newCurrentRow, true);
3432             }
3433          }
3434
3435          if(style.freeSelect)
3436             NotifyHighlight(master, this, currentRow, mods);
3437          else if((moveMultiple || (!(style.multiSelect) && previousRow == currentRow)) && 
3438             newCurrentRow && !(mods.shift))
3439          {
3440             if(!right)
3441             {
3442                if(!(mods.isActivate))
3443                {
3444                   if(style.moveRows)
3445                   {
3446                      this.dragRow = currentRow;
3447                      this.dropIndex = -1;
3448                      this.movedRow = false;
3449                   }
3450                   if(editData && editData.visible && style.alwaysEdit)
3451                   {
3452                      DataField field;
3453                      int sx = -scroll.x;
3454                      int indent = 0;
3455                      DataRow parent;
3456
3457                      if(style.collapse && !style.treeBranch)
3458                         sx += 15;
3459
3460                      for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3461                         if(!parent.header)
3462                            indent += (style.treeBranch) ? 20 : 15;
3463                      sx += indent;
3464
3465                      for(field = fields.first; field; field = field.next)
3466                      {
3467                         int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
3468                            clientSize.w - field.x : (field.width + EXTRA_SPACE);
3469
3470                         if(!field.prev) width -= indent;
3471                         if(x >= sx && x < sx + width)
3472                            break;                     
3473                         sx += width;
3474                      }
3475                      if(field == currentField)
3476                         editData.Deactivate();
3477                      else
3478                      {
3479                         currentRow.Edit(field);                     
3480                         editData.Activate();
3481                      }
3482                   }
3483                   else if(!(mods.ctrl) && numSelected <= 1)
3484                      this.editRow = currentRow;
3485
3486                   if(style.noDragging && newCurrentRow)
3487                     NotifyReclick(master, this, newCurrentRow, mods);
3488                }
3489                else
3490                {
3491                   // If the user clicked exactly on the edited field,
3492                   // activate it
3493                   if(editData && editData.visible && newCurrentRow)
3494                   {
3495                      DataField field, whichField;
3496                      int sx = -scroll.x;
3497                      int indent = 0;
3498
3499                      if(style.collapse && !(style.treeBranch))
3500                         sx += 15;
3501                   
3502                      whichField = currentField;
3503
3504                      {
3505                         DataRow parent;
3506                         for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3507                            if(!parent.header)
3508                               indent += (style.treeBranch) ? 20 : 15;
3509                         sx += indent;
3510                      }
3511
3512                      for(field = fields.first; field; field = field.next)
3513                      {
3514                         int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
3515                            clientSize.w - field.x : (field.width + EXTRA_SPACE);
3516                         if(!field.prev) width -= indent;
3517                         if(x >= sx && x < sx + width && newCurrentRow)
3518                            break;
3519                         sx += width;
3520                      }
3521
3522                      if(field) //x >= sx && x < sx + width && newCurrentRow)
3523                      {
3524                         if(field == currentField)
3525                            editData.Activate();
3526                         /*else
3527                            newCurrentRow.Edit(currentField);*/
3528                      }
3529                      else if(style.noDragging && newCurrentRow)
3530                        NotifyReclick(master, this, newCurrentRow, mods);
3531                   }
3532                   else if(style.noDragging && newCurrentRow)
3533                     NotifyReclick(master, this, newCurrentRow, mods);
3534                }
3535             }
3536          }
3537          else
3538          {
3539             result = NotifySelect(master, this, 
3540                currentRow ? currentRow : null, mods);
3541             if(result && style.alwaysEdit && currentRow)
3542             {
3543                if(newCurrentRow)
3544                {
3545                   DataField field = null;
3546                   int sx = -scroll.x;
3547                   int indent = 0;
3548                   DataRow parent;
3549
3550                   if(style.collapse && !style.treeBranch)
3551                      sx += 15;
3552
3553                   for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3554                      if(!parent.header)
3555                         indent += (style.treeBranch) ? 20 : 15;
3556                   sx += indent;
3557
3558                   for(field = fields.first; field; field = field.next)
3559                   {
3560                      int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
3561                         clientSize.w - field.x : (field.width + EXTRA_SPACE);
3562
3563                      if(!field.prev) width -= indent;
3564                      if(x >= sx && x < sx + width)
3565                      {
3566                         currentField = field;
3567                         break;
3568                      }
3569                      sx += width;
3570                   }
3571                }
3572                currentRow.Edit(currentField);
3573
3574                // If the user clicked exactly on the edited field,
3575                // activate it
3576                if(editData && editData.visible && newCurrentRow)
3577                {
3578                   if(currentField)
3579                   {
3580                      editData.Activate();
3581                   }
3582                   else if(style.noDragging && newCurrentRow)
3583                      NotifyReclick(master, this, newCurrentRow, mods);
3584                }
3585             }
3586             else if(style.noDragging && newCurrentRow)
3587               NotifyReclick(master, this, newCurrentRow, mods);
3588          }
3589       }
3590       /*
3591          For drop box to capture...
3592       else
3593       {
3594          if(x < 0 || y < 0 || x >= clientSize.w || y >= clientSize.h)
3595          {
3596             bool goOn = true;
3597             master.parent.Activate();
3598             Update(null);
3599             ReleaseCapture();
3600             return true;
3601          }
3602       }
3603       */
3604       if(result)
3605       {
3606          if(!style.noDragging)
3607          {
3608             this.dragging = true;
3609             Capture();
3610          }
3611          if(x >= 0 && y >= 0 && x < clientSize.w && y < clientSize.h)
3612             this.rolledOver = true;
3613          Update(null);
3614       }
3615       else
3616       {
3617          this.dragging = false;
3618          OnLeftButtonUp(x, y, mods);
3619       }
3620       return result;
3621    }
3622
3623    bool OnLeftButtonDown(int x, int y, Modifiers mods)
3624    {
3625       return OnButtonDown(x,y, mods, false);
3626    }
3627
3628    bool OnLeftButtonUp(int x, int y, Modifiers mods)
3629    {
3630       if(resizingField && style.alwaysEdit)
3631       {
3632          Window::FreeMouseRange();
3633          ReleaseCapture();
3634          resizingField = null;
3635       }
3636
3637       if(dragRow || editRow)
3638       {
3639          DataRow row, switchRow = rows.last;
3640          int rowY = (style.header) ? rowHeight : 0;
3641          for(row = firstRowShown; row; row = row.GetNextRow())
3642          {
3643             rowY += rowHeight;
3644             if(rowY > y) 
3645             {
3646                switchRow = row;
3647                break;
3648             }
3649          }
3650          if(this.editRow == switchRow && y >= 0)
3651          {
3652             // Find which field
3653             DataField field;
3654             int fieldX = 0;
3655             for(field = fields.first; field; field = field.next)
3656             {
3657                int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ? 
3658                   clientSize.w - field.x : (field.width + EXTRA_SPACE);
3659                fieldX += width;
3660
3661                if(fieldX > x + scroll.x) 
3662                   break;
3663             }
3664             
3665             if(field && field.editable)
3666             {
3667                // true: destroy edit box
3668                HideEditBox(true, true, false);
3669                PopupEditBox(field, false);
3670             }
3671             else if(!style.noDragging)
3672                NotifyReclick(master, this, currentRow, mods);
3673          }
3674          else if(style.moveRows && switchRow)
3675          {
3676             if(this.dragRow == switchRow && this.movedRow == false)
3677             {
3678                DataRow row = this.dragRow;
3679                DataRow selRow;
3680                if(!(mods.ctrl))
3681                {
3682                   for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3683                      selRow.selectedFlag = unselected;
3684                }
3685                else
3686                {
3687                   for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3688                   {
3689                      if(selRow != clickedRow)
3690                      {
3691                         if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3692                         else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3693                      }
3694                   }
3695                }
3696                if(mods.ctrl)
3697                {
3698                   if(row.selectedFlag)
3699                      row.selectedFlag = tempUnselected;
3700                   else row.selectedFlag = tempSelected;
3701                }
3702                else
3703                   row.selectedFlag = tempSelected;
3704                clickedRow = row;
3705             }
3706             else
3707             { 
3708                if(style.multiSelect)
3709                {
3710                   if(!switchRow.selectedFlag)
3711                   {
3712                      bool foundSwitch = false;
3713                      bool after = false;
3714                      DataRow next;
3715                      DataRow afterRow = switchRow.prev;
3716                      for(row = rows.first; row; row = next)
3717                      {
3718                         next = row.GetNextRow();
3719                         if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
3720                         {
3721                            if(!foundSwitch && !after)
3722                            {
3723                               after = true;
3724                               afterRow = switchRow;
3725                            }
3726                            if(!after || !(row.selectedFlag == selected || row.selectedFlag == tempSelected) ||
3727                               !foundSwitch)
3728                            {
3729                               row.Move(afterRow);
3730                               afterRow = row;
3731                            }
3732                         }
3733                         else if(row == switchRow)
3734                            foundSwitch = true;
3735                      }
3736                   }
3737                }
3738                else
3739                {
3740                   for(row = rows.first; row; row = row.GetNextRow())
3741                   {
3742                      if(row == switchRow || row == this.dragRow)
3743                         break;
3744                   }
3745
3746                   // Switch row first: move before
3747                   if(row == switchRow)
3748                   {
3749                      if(NotifyMove(master, this, switchRow.prev, mods))
3750                         dragRow.Move(switchRow.prev);
3751                   }
3752                   // Dragged row first: move after
3753                   else
3754                   {
3755                      if(NotifyMove(master, this, switchRow, mods))
3756                         dragRow.Move(switchRow);
3757                   }
3758                }
3759             }
3760          }
3761          dragRow = null;
3762          editRow = null;
3763          movedRow = false;
3764          dropIndex = -1;
3765          Update(null);
3766       }
3767
3768       timer.Stop();
3769       if(this.dragging || style.freeSelect)
3770       {
3771          if(this.dragging)
3772          {
3773             this.rolledOver = this.dragging = false;
3774          }
3775          if(x >= 0 && y >= 0 && x < clientSize.w && y < clientSize.h && currentRow && style.freeSelect)
3776          {
3777             bool result;
3778             ReleaseCapture();
3779             result = NotifySelect(master, this, currentRow, mods);
3780             if(style.alwaysEdit)
3781                currentRow.Edit(currentField);
3782             return result;
3783
3784          }
3785          // if(!(style.freeSelect))
3786          ReleaseCapture();
3787       }
3788       return true;
3789    }
3790
3791    bool OnLeftDoubleClick(int x, int y, Modifiers mods)
3792    {
3793       int rowStart = -scroll.x;
3794       DataRow row;
3795       int rowY = (style.header) ? rowHeight : 0;
3796       int plusIndent = 0;
3797
3798       OnLeftButtonUp(x,y,mods);
3799       if(style.alwaysEdit)
3800       {
3801          if(!(style.collapse) || x > 15)
3802             if(editData && editData.visible)
3803             {
3804                editData.Activate();
3805                NotifyDoubleClick(master, this, x, y, mods);
3806                return false;
3807             }
3808       }
3809       for(row = firstRowShown; row; row = row.GetNextRow())
3810       {
3811          rowY += rowHeight;
3812          if(rowY > y || (style.multiSelect && !row.GetNextRow())) 
3813          {
3814             if(style.treeBranch)
3815             {
3816                DataRow parent;
3817                for(parent = (style.rootCollapse) ? row.parent : (row.parent ? row.parent.parent : null); parent; parent = parent.parent)
3818                   if(!parent.header)
3819                      plusIndent += 20;
3820                plusIndent += 4;
3821             }
3822             break;
3823          }
3824       }
3825
3826       if((row && style.collapse && (x >= rowStart && x <= rowStart + 18 + plusIndent)) ||
3827          NotifyDoubleClick(master, this, x, y, mods))
3828       {
3829          if(style.collapse)
3830          {
3831             if(row && row.subRows.first)
3832             {
3833                row.collapsed = !row.collapsed;
3834                return false;
3835             }
3836          }
3837          // We need to return true here so that OnLeftButtonDown can popup the DataBox Editors
3838          return true;
3839       }
3840       return false;
3841    }
3842
3843    bool OnRightButtonDown(int x, int y, Modifiers mods)
3844    {
3845       return OnButtonDown(x,y, mods, true);
3846    }
3847
3848    bool OnRightButtonUp(int x, int y, Modifiers mods)
3849    {
3850       OnLeftButtonUp(x,y,mods);
3851       return NotifyRightClick(master, this, x, y, mods);
3852    }
3853
3854    bool GoToLetter(unichar ch, bool keyHit)
3855    {
3856       bool result = false;
3857       DataField field;
3858       bool checkNextField = true;
3859       int len = keyHit ? 0 : strlen(typedString);
3860
3861       typedString = renew typedString char[len + 2];
3862       typedString[len++] = (char)tolower(ch);         // TODO: FIX UNICODE
3863       typedString[len] = '\0';
3864
3865       for(field = fields.first; field; field = field.next)
3866       {
3867          DataRow startRow = currentRow ? currentRow : rows.first;
3868
3869          if(startRow && field.dataType && field.dataType._vTbl[__ecereVMethodID_class_OnGetString] && ch)
3870          {
3871             DataRow row, next;
3872             bool looped = false;
3873             if(len == 1 && currentRow)
3874                startRow = (next = startRow.GetNextRow(), (next ? next : rows.first));
3875         
3876             for(row = startRow; row != startRow || !looped; next = row.GetNextRow(), row = next ? next : rows.first)
3877             {
3878                void * data = row.GetData(field);
3879                char tempString[1024] = "";
3880                bool needClass = false;
3881                char * string = data ? (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass) : null;
3882
3883                if(string && string[0])
3884                   checkNextField = false;
3885                if(string && string[0] && !strnicmp(string, typedString, len))
3886                {
3887                   if(style.multiSelect)
3888                   {
3889                      DataRow selRow;
3890                      bool foundRow = false;
3891
3892                      //this.clickedRowIndex = 0;
3893                      clickedRow = row;
3894                      for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3895                      {
3896                         if(selRow == row) foundRow = true;
3897                         selRow.selectedFlag = unselected;
3898                         //if(!foundRow) this.clickedRowIndex++;
3899                      }
3900                      row.selectedFlag = selected;
3901                   }
3902                   SetCurrentRow(row, true);
3903                   result = true;
3904                   break;
3905                }
3906                looped = true;
3907             }
3908             typingTimer.Stop();
3909             if(this.typingTimeOut && !keyHit)
3910                typingTimer.Start();
3911             if(!result || !this.typingTimeOut || keyHit)
3912                typedString[len-1] = '\0';
3913          }
3914          if(!checkNextField || result) break;
3915       }
3916       return result;
3917    }
3918
3919    bool OnKeyDown(Key key, unichar ch)
3920    {
3921       DataField field;
3922
3923       if(key == enter || key == keyPadEnter)
3924       {
3925          if(editData && editData.visible && editData.active)
3926          {
3927             HideEditBox(true, false, false);
3928             return false;
3929          }
3930       }
3931       else if(key == escape)
3932       {
3933          if(resizingField || this.movingFields || (editData && editData.visible) || this.dragRow)
3934          {
3935             if(editData && editData.visible && style.alwaysEdit && !editData.active)
3936                return true;
3937             // false: dont destroy edit box
3938             HideEditBox(false, false, false);
3939             if(resizingField)
3940             {
3941                resizingField.width = this.startWidth;
3942                AdaptToFieldWidth(resizingField, true);
3943                resizingField = null;
3944                ReleaseCapture();
3945             }
3946             this.dragRow = null;
3947             if(this.dragging)
3948             {
3949                this.dragging = false;
3950                ReleaseCapture();
3951             }
3952
3953             this.movingFields = false;
3954             draggingField = null;
3955             Update(null);
3956             return false;
3957          }      
3958       }
3959
3960       if(!currentField || !currentField.editable)            
3961          for(field = fields.first; field; field = field.next)
3962          {
3963             if(field.editable)
3964             {
3965                currentField = field;
3966                break;
3967             }
3968          }
3969       if(key == f2 && currentField && currentField.editable)
3970       {
3971          PopupEditBox(currentField, false);
3972          if(editData && editData.visible)
3973          {
3974             if(style.alwaysEdit)
3975                editData.Activate();
3976             return false;
3977          }
3978       }
3979  
3980       if(!NotifyKeyDown(master, this, currentRow, key, ch))
3981          return false;
3982
3983       // Editable fields...
3984       if(currentField)
3985       {
3986          if(style.alwaysEdit && editData && editData.visible)
3987             return editData.OnKeyDown(key, ch);
3988          return true;   // We want to pick up the OnKeyHit to replace contents, but skip GoToLetter
3989       }
3990       
3991       if(ch != 128 && !key.alt && !key.ctrl && GoToLetter(ch, false))
3992       {
3993          /*if(inactive && window.state != Hidden)
3994             NotifyHighlight(master, this, currentRow, 0);
3995          else
3996          {
3997             NotifySelect(master, this, currentRow, 0);
3998          }*/
3999          return false;
4000       }
4001       return true;
4002    }
4003
4004    bool OnKeyHit(Key key, unichar ch)
4005    {
4006       if(!ch && !key.alt && !key.ctrl)
4007       {
4008          key.code = (SmartKey)key.code;
4009       }
4010       if(ch >= 32 && !key.alt && !key.ctrl && ch != 128)
4011       {
4012          DataField field;
4013          if(!currentField || !currentField.editable)
4014             for(field = fields.first; field; field = field.next)
4015             {
4016                if(field.editable)
4017                {
4018                   currentField = field;
4019                   break;
4020                }
4021             }
4022          if(currentField && currentField.editable)
4023          {
4024             if((!editData || !editData.visible) || !editData.active)
4025             {
4026                PopupEditBox(currentField, false);
4027                if(editData && editData.visible)
4028                {
4029                   editData.Activate();
4030                   editData.OnKeyHit(key, ch);
4031                }
4032             }
4033             return false;
4034          }
4035       }
4036
4037       if(!(style.multiSelect) && (key.ctrl))
4038          return true;
4039
4040       if(editData && editData.visible && ch && !key.alt && !key.ctrl && editData.active)
4041          return false;
4042
4043       switch(key.code)
4044       {
4045          case left:
4046             if(style.alwaysEdit)
4047             {
4048                if(currentField)
4049                {
4050                   DataField field;
4051                   for(field = currentField.prev; field; field = field.prev)
4052                   {
4053                      if(field.editable)
4054                      {
4055                         currentField = field;
4056                         HideEditBox(true, true, false);
4057                         PopupEditBox(currentField, false);
4058                         return false;
4059                      }                     
4060                   }
4061                }
4062             }
4063             if(style.collapse && currentRow /*&& !currentField*/)  // THIS PREVENTED COLLAPSING THE PROPERTY SHEET
4064             {
4065                if(currentRow.subRows.first && !currentRow.collapsed)
4066                {
4067                   currentRow.collapsed = true;
4068                }
4069                else if(currentRow.parent)
4070                   SetCurrentRow(currentRow.parent, true);
4071                return false;
4072             }
4073             break;
4074          case right:
4075             if(style.collapse && currentRow && currentRow.subRows.first)
4076             {
4077                if(currentRow.collapsed)
4078                   currentRow.collapsed = false;
4079                else
4080                   SetCurrentRow(currentRow.subRows.first, true);
4081                return false;
4082             }
4083             else if(style.alwaysEdit)
4084             {
4085                if(currentField)
4086                {
4087                   DataField field;
4088                   for(field = currentField.next; field; field = field.next)
4089                   {
4090                      if(field.editable)
4091                      {
4092                         currentField = field;
4093                         HideEditBox(true, true, false);
4094                         PopupEditBox(currentField, false);
4095                         break;
4096                      }                     
4097                   }
4098                }
4099             }
4100             break;
4101          case down: case up:
4102          case pageDown: case pageUp:
4103          case end: case home:
4104          {
4105             int headerSize = ((style.header) ? rowHeight : 0);
4106             int height = clientSize.h + 1 - headerSize;
4107             DataRow oldRow;
4108
4109             // true: destroy edit box
4110             // !!! TESTING true HERE !!!
4111             HideEditBox(true, true, false);
4112             // HideEditBox(false, true, false);
4113             
4114             oldRow = currentRow;
4115
4116             SNAPDOWN(height, rowHeight);
4117             if((!currentRow || key.code == home) && key.code != end)
4118             {
4119                currentRow = rows.first;
4120             }
4121             else
4122             {
4123                DataRow next;
4124                switch(key.code)
4125                {
4126                   case down:
4127                      if(!(style.multiSelect) && currentRow && !currentRow.selectedFlag)
4128                         next = currentRow;
4129                      else
4130                         next = currentRow.GetNextRow();
4131                      if(next)
4132                      {
4133                         currentRow = next;
4134                      }
4135                      break;
4136                   case up:
4137                      if(!(style.multiSelect) && currentRow && !currentRow.selectedFlag)
4138                         next = currentRow;
4139                      else
4140                         next = currentRow.GetPrevRow();
4141
4142                      if(next)
4143                      {
4144                         currentRow = next;
4145                      }
4146                      break;
4147                   case end:
4148                      // TODO: Find very last row
4149                      for(currentRow = rows.last; currentRow && !currentRow.collapsed && currentRow.subRows.last;)
4150                         currentRow = currentRow.subRows.last;
4151                      break;
4152                   case pageUp:
4153                   {
4154                      int c;
4155                      for(c = 0;
4156                      currentRow && (next = currentRow.GetPrevRow()) && c < height / rowHeight;
4157                          c++, currentRow = next);
4158                      break;
4159                   }
4160                   case pageDown:
4161                   {
4162                      int c;
4163                      for(c = 0;
4164                          currentRow && (next = currentRow.GetNextRow()) && c < height / rowHeight;
4165                          c++, currentRow = next);
4166                      break;
4167                   }
4168                }
4169             }
4170             if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
4171                SetScrollPosition(scroll.x, currentRow.index * rowHeight - height + rowHeight);
4172             else if(!currentRow || currentRow.index * rowHeight < scroll.y)
4173                SetScrollPosition(scroll.x, currentRow ? currentRow.index * rowHeight : 0);
4174
4175             if(style.multiSelect)
4176             {
4177                DataRow selRow;
4178
4179                if(!(key.shift) && (key.ctrl))
4180                {
4181                   DataRow row;
4182                   for(row = rows.first; row; row = row.GetNextRow())
4183                   {
4184                      if(row.selectedFlag == tempSelected)
4185                         row.selectedFlag = selected;
4186                      else if(row.selectedFlag == tempUnselected)
4187                         row.selectedFlag = unselected;
4188                   }
4189                }
4190
4191                if(!(key.ctrl))
4192                {
4193                   for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4194                      selRow.selectedFlag = unselected;
4195                }
4196                else
4197                {
4198                   for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4199                   {
4200                      if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
4201                      else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
4202                   }
4203                }
4204
4205                if(key.shift)
4206                {
4207                   if(currentRow.index >= clickedRow.index)
4208                   {
4209                      for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
4210                      {
4211                         if(key.ctrl)
4212                         {
4213                            if(selRow.selectedFlag) selRow.selectedFlag = tempUnselected; else selRow.selectedFlag = tempSelected;
4214                         }
4215                         else
4216                            selRow.selectedFlag = selected;
4217                         if(selRow == currentRow)
4218                            break;
4219                      }
4220                   }
4221                   else
4222                   {
4223                      for(selRow = currentRow; selRow; selRow = selRow.GetNextRow())
4224                      {
4225                         if(key.ctrl)
4226                         {
4227                            if(selRow.selectedFlag) selRow.selectedFlag = tempUnselected; else selRow.selectedFlag = tempSelected;
4228                         }
4229                         else
4230                            selRow.selectedFlag = selected;
4231                         if(selRow == clickedRow)
4232                            break;
4233                      }
4234                   }
4235                }
4236                else
4237                {
4238                   if(!(key.ctrl) && currentRow)
4239                   {
4240                      currentRow.selectedFlag = selected;
4241                   }
4242
4243                   clickedRow = currentRow;
4244                }
4245             }
4246             else
4247             {
4248                if(oldRow) oldRow.selectedFlag = unselected;
4249                if(currentRow) currentRow.selectedFlag = selected;
4250             }
4251
4252             if(currentRow)
4253             {
4254                if(style.freeSelect)
4255                   NotifyHighlight(master, this, currentRow, 0);
4256                else
4257                   NotifySelect(master, this, currentRow, 0);
4258
4259                if(style.alwaysEdit && currentRow)
4260                   currentRow.Edit(currentField /*null*/);
4261             }
4262             Update(null);
4263             return false;
4264          }
4265          case space:
4266          {
4267             if(style.multiSelect && currentRow)
4268             {
4269                if(currentRow.selectedFlag)
4270                {
4271                   if(key.ctrl)
4272                      currentRow.selectedFlag = unselected;
4273                }
4274                else
4275                   currentRow.selectedFlag = selected;
4276                Update(null);
4277
4278                if(style.freeSelect)
4279                   NotifyHighlight(master, this, currentRow, 0);
4280                else
4281                   NotifySelect(master, this, currentRow, 0);
4282             }
4283             break;
4284          }
4285       }
4286  
4287       if(!NotifyKeyHit(master, this, currentRow, key, ch))
4288          return false;
4289
4290       if(ch != 128 && !key.alt && !key.ctrl && GoToLetter(ch, true))
4291       {
4292          /*if(inactive && window.state != Hidden)
4293             return NotifyHighlight(master, this, currentRow, 0);
4294          else
4295          {
4296             return NotifySelect(master, this, currentRow, 0);
4297          }*/
4298          return false;
4299       }
4300       return true;
4301    }
4302
4303
4304    void OnHScroll(ScrollBarAction action, int position, Key key)
4305    {
4306       Update(null);
4307    }
4308
4309    void OnVScroll(ScrollBarAction action, int position, Key key)
4310    {
4311       int y = 0;
4312       DataRow next;
4313
4314       for(firstRowShown = rows.first; firstRowShown; firstRowShown = next)
4315       {
4316          next = firstRowShown.GetNextRow();
4317          if(y >= position || !next) break;
4318
4319          y += rowHeight;
4320       }
4321       Update(null);
4322    }
4323
4324    OldList fields;
4325    OldList rows;
4326    int numFields;
4327    DataRow firstRowShown;
4328    DataRow clickedRow;
4329    DataRow currentRow;
4330    int width;
4331    DataField sortField;
4332    int rowCount;
4333    int rowHeight;
4334    int fontH;
4335    double typingTimeOut;
4336    char * typedString;
4337
4338    int mouseX, mouseY;
4339
4340    Timer timer
4341    {
4342       delay = 0.1;
4343       userData = this;
4344
4345       bool DelayExpired()
4346       {
4347          Modifiers mods { };
4348          if(guiApp.GetKeyState(shift)) mods.shift = true;
4349          if(guiApp.GetKeyState(alt)) mods.alt = true;
4350          if(guiApp.GetKeyState(control)) mods.ctrl = true;
4351          OnMouseMove(MAXINT, MAXINT, mods);
4352
4353          return true;
4354       }
4355    };
4356
4357    Timer typingTimer
4358    {
4359       delay = 0.5; // typingTimeOut
4360       userData = this;
4361       
4362       bool DelayExpired()
4363       {
4364          typedString[0] = '\0';
4365
4366          // The next line was commented... Why? When commented typing words stops working ( only first character jumps )
4367          typingTimer.Stop();
4368          return true;
4369       }
4370    };
4371
4372    bool dragging, rolledOver;
4373    int numSelections;
4374    Button endBevel;
4375
4376    // For moving rows
4377    DataRow dragRow;
4378    int dropIndex;
4379    bool movedRow;
4380
4381    // For editing fields
4382    DataBox editData;
4383    DataField currentField;
4384    DataRow editRow;
4385
4386    // For moving fields
4387    DataField draggingField, dropField;
4388    bool movingFields;
4389
4390    // For resizing fields
4391    DataField resizingField;
4392    int resizeX, oldX, startWidth;
4393
4394    ListBoxBits style;
4395    FontResource boldFont;
4396    int maxShown;
4397
4398    // Only used for OnMouseMove so far, for avoiding problems with consequential mouse moves
4399    bool insideNotifySelect;
4400    Color selectionColor, selectionText, stippleColor;
4401    stippleColor = 0xFFFFFF80;
4402 };