1 namespace gui::controls;
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;
10 #define SNAPDOWN(x, d) \
13 if(x < 0) x -= ((d) - Abs(x) % (d)); else x -= x % (d); \
18 static class ListBoxCell : struct
20 ListBoxCell prev, next;
26 #define RESIZE_BORDER 5
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;
37 public class DataDisplayFlags
39 public bool selected:1, fullRow:1, current:1, active:1, dropBox:1, header:1, firstField:1;
42 enum SelectedFlag { unselected, selected, tempSelected, tempUnselected };
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;
55 public class DataField
59 property Class dataType
61 set { dataType = value; if(value) { alignment = (Alignment)value.defaultAlignment; } } // NOTE: Class::defaultAlignment does not seem to be used anywhere
62 get { return dataType; }
64 property bool editable { set { editable = value; } };
65 property bool fixed { set { fixed = value; } get { return fixed; } };
66 property Alignment alignment
71 if(headButton) headButton.alignment = value;
72 if(listBox) listBox.Update(null);
74 get { return alignment; }
80 width = Max(value, -EXTRA_SPACE);
82 listBox.AdaptToFieldWidth(this, false);
86 property int index { get { return this ? index : 0; } };
95 for(field = listBox.fields.first; field; field = field.next)
97 if(index == value - 2)
110 for(field = listBox.fields.first; field; field = field.next)
122 property int sortOrder { get { return this ? sortOrder : 0; } };
123 property const char * header
129 headButton.text = header;
132 property void * userData
140 return this ? userData : null;
143 property bool freeData
145 set { freeData = value; } get { return freeData; }
147 property DataField prev { get { return prev; } };
148 property DataField next { get { return next; } };
150 void Move(DataField after)
154 listBox.fields.Move(this, after);
157 listBox.OnResize(listBox.clientSize.w, listBox.clientSize.h);
158 listBox.Update(null);
164 if(listBox && dataType)
166 Display display = listBox.display;
167 Font boldFont = listBox.boldFont.font;
168 Font font = listBox.fontObject;
172 display.FontExtent(boldFont, header, strlen(header), &width, null);
173 width += EXTRA_SPACE;
174 for(row = listBox.firstRow; row; row = row.GetNextRow())
178 for(i = 0, cell = row.cells.first; i != index; i++, cell = cell.next);
179 if(cell && cell.isSet && dataType)
181 static char tempString[4096];
184 if(dataType.type == normalClass || dataType.type == noHeadClass)
185 string = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, cell.data[0], tempString, userData, null);
187 string = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, cell.data, tempString, userData, null);
189 display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, null);
191 display.FontExtent(row.header ? boldFont : font, "", 0, &tw, null);
192 if(tw > width) width = tw;
196 property::width = width;
203 // property::dataType = "String";
204 property::dataType = "char *";
216 headButton.Destroy(0);
221 listBox.fields.Remove(this);
222 for(field = listBox.fields.first; field; field = field.next)
224 if(field.index >= index)
227 if(listBox.currentField == this)
228 listBox.currentField = null;
230 listBox.OnResize(listBox.clientSize.w, listBox.clientSize.h);
235 DataField prev, next;
259 property int64 tag { set { if(this) tag = value; } get { return this ? tag : 0; } };
260 property DataRow previous { get { return prev; } };
261 property DataRow next { get { return next; } };
262 property int index { get { return (this && (!parent || parent.IsExpanded())) ? index : -1; } };
263 property const char * string
265 set { SetData(listBox.fields.first, value); }
266 get { return GetData(listBox.fields.first); }
268 property bool isHeader { set { header = value; } get { return this ? header : false; } };
269 property BitmapResource icon { set { if(this) icon = value; } get { return this ? icon : null; } };
270 property bool collapsed
274 if(this && collapsed != value)
277 if(parent.IsExpanded())
284 for(search = subRows.first; search; search = search.next)
285 search.selectedFlag = 0;
287 if(listBox.clickedRow && !listBox.clickedRow.parent.IsExpanded())
289 listBox.clickedRow = GetNextRow();
290 if(!listBox.clickedRow)
291 listBox.clickedRow = this;
293 if(listBox.currentRow && !listBox.currentRow.parent.IsExpanded())
295 listBox.SetCurrentRow(this, true);
297 if(listBox.firstRowShown && !listBox.firstRowShown.parent.IsExpanded())
299 listBox.firstRowShown = GetPrevRow();
300 if(!listBox.firstRowShown)
301 listBox.firstRowShown = this;
306 for(search = GetNextRow(); search; search = search.GetNextRow())
308 listBox.rowCount = ix;
310 listBox.HideEditBox(false, false, true);
312 listBox.SetScrollArea(
314 (listBox.rowCount * listBox.rowHeight) +
315 ((listBox.style.header) ? listBox.rowHeight : 0) -
316 ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
317 listBox.Update(null);
318 listBox.NotifyCollapse(listBox.master, listBox, this, value);
322 if(this && !skipCheck)
323 listBox.CheckConsistency();
326 get { return this ? collapsed : false; }
328 property bool selected
334 selectedFlag = value ? selected : unselected;
335 listBox.Update(null);
338 get { return selectedFlag == selected || selectedFlag == tempSelected; }
340 property DataRow parent
344 if(this && (value != this))
347 DataRow after = value ? value.subRows.last : listBox.rows.last;
348 int ixCount = (!collapsed && subRows.count) ? GetLastRow().index - index + 1 : 1;
349 if(parent.IsExpanded())
351 for(search = GetNextRow(); search; search = search.GetNextRow())
352 search.index -= ixCount;
353 listBox.rowCount -= ixCount;
356 listBox.HideEditBox(false, false, true);
359 if(this == listBox.clickedRow)
361 listBox.clickedRow = GetNextRow();
362 if(!listBox.clickedRow)
363 listBox.clickedRow = GetPrevRow();
366 if(this == listBox.currentRow)
368 DataRow newCurrentRow = GetNextRow();
369 if(!listBox.newCurrentRow)
370 listBox.newCurrentRow = GetPrevRow();
371 listBox.SetCurrentRow(newCurrentRow, true);
374 if(this == listBox.firstRowShown)
376 listBox.firstRowShown = GetPrevRow();
377 if(!listBox.firstRowShown)
378 listBox.firstRowShown = GetNextRow();
382 (parent ? parent.subRows : listBox.rows).Remove(this);
385 value.subRows.Insert(after, this);
387 listBox.rows.Insert(after, this);
391 if(value && listBox.style.expandOnAdd)
394 value.skipCheck = true;
396 value.collapsed = false;
398 value.skipCheck = false;
402 if(value.IsExpanded())
406 if(after && after.subRows.first && !after.collapsed)
408 search = after.GetLastRow();
409 index = search.index + 1;
412 index = after ? (after.index + 1) : (index + 1);
414 listBox.rowCount += ixCount;
418 for(search = GetNextRow(); search; search = search.GetNextRow())
422 listBox.SetScrollArea(
424 (listBox.rowCount * listBox.rowHeight) +
425 ((listBox.style.header) ? listBox.rowHeight : 0) -
426 ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
427 if(listBox.style.autoScroll)
428 listBox.SetScrollPosition(0, MAXINT - listBox.rowHeight);
430 // TESTING THIS HERE...
432 listBox.Sort(listBox.sortField, listBox.sortField.sortOrder);
435 int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
436 int height = listBox.clientSize.h + 1 - headerSize;
437 if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
438 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
439 else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
441 int line = listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0;
442 listBox.SetScrollPosition(listBox.scroll.x, line);
445 listBox.OnVScroll(0, listBox.scroll.y, 0);
447 listBox.Update(null);
455 property DataRow lastRow { get { return this ? subRows.last : null; } };
456 property DataRow firstRow { get { return this ? subRows.first : null; } };
458 void Edit(DataField field)
464 if(!field || !field.editable)
466 for(field = listBox.fields.first; field; field = field.next)
467 if(field.editable) break;
469 if(field && field.editable)
471 listBox.SetCurrentRow(this, true);
472 listBox.PopupEditBox(field, false);
478 // NOTE: This does not support reparenting (Use row.parent = first)
479 void Move(DataRow after)
484 if(listBox && prev != after)
487 int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
488 int height = listBox.clientSize.h + 1 - headerSize;
489 int ixCount = (!collapsed && subRows.count) ? GetLastRow().index - index + 1 : 1;
491 if(!after || after.index < index)
493 if((after && after == listBox.firstRowShown.prev) || (!after && !parent /*&& listBox.firstRowShown.prev*/))
494 listBox.firstRowShown = this;
496 // All rows between AFTER (exclusive) and ROW (exclusive) are incremented by one
497 // ROW is equal to AFTER's index + 1
499 for(search = after ? after.next : (parent ? parent.subRows.first : listBox.rows.first); search && search != this; search = search.GetNextRow())
500 search.index += ixCount;
502 if(after && after.subRows.first && !after.collapsed)
504 search = after.GetLastRow();
505 index = search.index + 1;
508 index = after ? (after.index + 1) : parent ? parent.index + 1 : 0;
510 // Fix indices of sub rows
514 for(c = 1, search = GetNextRow(); search && c < ixCount; c++, search = search.GetNextRow())
521 int afterIXCount = 1;
523 nextRow = GetNextRow();
524 if(this == listBox.firstRowShown)
525 listBox.firstRowShown = nextRow;
527 // All rows between ROW (exclusive) and AFTER (inclusive) are decremented by one
528 // ROW is equal to AFTER's index
530 for(search = nextRow; search; search = search.GetNextRow())
532 search.index -= ixCount;
533 if(search == after) break;
536 // Fix up's after's sub rows
537 if(after && !after.collapsed)
539 DataRow last = after.GetLastRow();
542 int ix = after.index+1;
543 for(search = after.GetNextRow(); search; search = search.GetNextRow())
547 if(search == last) break;
551 index = after.index + afterIXCount;
553 // Fix indices of sub rows
557 for(c = 1, search = GetNextRow(); search && c < ixCount; c++, search = search.GetNextRow())
561 (parent ? parent.subRows : listBox.rows).Move(this, after);
564 listBox.CheckConsistency();
567 listBox.HideEditBox(true, false, true);
570 if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
571 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
572 else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
574 int line = listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0;
575 //SNAPUP(line, listBox.rowHeight);
576 listBox.SetScrollPosition(listBox.scroll.x, line);
579 listBox.OnVScroll(0, listBox.scroll.y, 0);
581 listBox.modifiedDocument = true;
583 listBox.Update(null);
590 any_object GetData(DataField field)
594 ListBoxCell cell = listBox.GetCell(&this, &field);
595 if(cell && cell.isSet && cell.data)
597 if((field.dataType.type == normalClass || field.dataType.type == noHeadClass))
606 void * SetData(DataField field, any_object newData)
610 ListBoxCell cell = listBox.GetCell(&this, &field);
613 Class dataType = field.dataType;
617 if(dataType.type == normalClass || dataType.type == noHeadClass)
619 if(cell.data[0] && field.freeData)
620 ((void (*)(void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnFree])(dataType, cell.data[0]);
622 if(eClass_IsDerived(dataType, class(char *)) && field.freeData)
623 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCopy])(dataType, cell.data, newData);
625 cell.data[0] = (void *)newData;
629 // Free old data first
630 ((void (*)(void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnFree])(dataType, cell.data);
631 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCopy])(dataType, cell.data, newData);
635 listBox.modifiedDocument = true;
636 listBox.Update(null);
637 if(dataType && (dataType.type == normalClass || dataType.type == noHeadClass))
646 void UnsetData(DataField field)
650 ListBoxCell cell = listBox.GetCell(&this, &field);
653 Class dataType = field.dataType;
657 if(dataType.type == normalClass || dataType.type == noHeadClass)
659 if(cell.data[0] && field.freeData)
660 ((void (*)(void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnFree])(dataType, cell.data[0]);
665 int size = (field.dataType && field.dataType.typeSize) ?
666 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
667 // Free old data first
668 ((void (*)(void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnFree])(dataType, cell.data);
669 FillBytes(cell.data, 0, size - (uint)(uintptr)&((ListBoxCell)0).data);
673 listBox.Update(null);
678 DataRow FindRow(int64 tag)
681 for(row = subRows.first; row; row = row.next)
683 if(!row.noneRow && row.tag == tag)
689 DataRow FindSubRow(int64 tag)
692 for(row = subRows.first; row; row = row.next)
694 if(!row.noneRow && row.tag == tag)
696 if(row.subRows.first)
698 DataRow subRow = row.FindSubRow(tag);
706 DataRow AddRowAfter(DataRow after)
716 subRows.Insert(after, row);
717 row.listBox = listBox;
721 for(c = 0; c<listBox.fields.count; c++)
723 for(field = listBox.fields.first; field; field = field.next)
724 if((int)field.index == c)
728 int size = (field.dataType && field.dataType.typeSize) ?
729 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
730 ListBoxCell cell = (ListBoxCell)new0 byte[size];
732 FillBytes(cell.data, 0, size - (uint)(uintptr)&((ListBoxCell)0).data);
741 if(after && after.subRows.first && !after.collapsed)
743 for(search = after.subRows.last; !search.collapsed && search.subRows.last; )
744 search = search.subRows.last;
745 row.index = search.index + 1;
748 row.index = after ? (after.index + 1) : (index + 1);
752 for(search = row.GetNextRow(); search; search = search.GetNextRow())
755 listBox.SetScrollArea(
757 (listBox.rowCount * listBox.rowHeight) +
758 ((listBox.style.header) ? listBox.rowHeight : 0) -
759 ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
760 if(listBox.style.autoScroll)
761 listBox.SetScrollPosition(0, MAXINT - listBox.rowHeight);
764 listBox.modifiedDocument = true;
767 listBox.CheckConsistency();
777 return AddRowAfter(subRows.last);
781 DataRow AddStringf(const char * format, ...)
786 char string[MAX_F_STRING];
788 va_start(args, format);
789 vsnprintf(string, sizeof(string), format, args);
790 string[sizeof(string)-1] = 0;
794 row.SetData(null, string);
800 DataRow AddString(const char * string)
806 row.SetData(listBox.fields.first, string);
816 subRows.offset = (uint)(uintptr)&((DataRow)0).prev;
821 ListBoxCell cell, next;
826 while((subRow = subRows.first))
828 subRows.Remove(subRow);
832 for(cell = cells.first; cell; cell = next, cellIndex++)
837 for(field = listBox.fields.first; field && field.index != cellIndex; field = field.next);
838 if(field && field.dataType)
840 // TOCHECK: Is this check good? Will need incref/decref sometime?
841 if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
843 if(cell.data[0] && field.freeData)
844 ((void (*)(void *, void *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnFree])(field.dataType, cell.data[0]);
847 ((void (*)(void *, void *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnFree])(field.dataType, cell.data);
857 return !this || (!collapsed && (!parent || parent.IsExpanded()));
860 int Compare(DataRow b, DataField sortField)
863 ListBoxCell cell1, cell2;
865 for(index = 0, cell1 = cells.first, cell2 = b.cells.first;
866 index != sortField.index;
867 index++, cell1 = cell1.next, cell2 = cell2.next);
869 if(!cell1.isSet && !cell2.isSet)
871 else if(!cell1.isSet)
873 else if(!cell2.isSet)
876 if(noneRow && !b.noneRow) return -1;
877 else if(!noneRow && b.noneRow) return 1;
878 else if(noneRow && b.noneRow) return 0;
880 if(sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare])
882 if(sortField.dataType.type == normalClass || sortField.dataType.type == noHeadClass)
884 result = ((int (*)(void *, void *, void *))(void *)sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare])(sortField.dataType,
885 (cell1.isSet && cell1.data) ? cell1.data[0] : null,
886 (cell2.isSet && cell2.data) ? cell2.data[0] : null);
890 result = ((int (*)(void *, void *, void *))(void *)sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare])(sortField.dataType,
891 cell1.isSet ? cell1.data : null,
892 cell2.isSet ? cell2.data : null);
895 return sortField.sortOrder * result;
898 void _SortSubRows(DataField field, int order)
901 for(search = subRows.first; search; search = search.next)
902 search._SortSubRows(field, order);
903 subRows.Sort(Compare, field);
906 public void SortSubRows(bool scrollToCurrent)
908 if(this && listBox && listBox.sortField)
910 _SortSubRows(listBox.sortField, listBox.sortField.sortOrder);
915 for(search = this; search; search = search.GetNextRow())
920 int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
921 int height = listBox.clientSize.h + 1 - headerSize;
922 if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
923 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
924 else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
925 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0);
926 listBox.OnVScroll(0, listBox.scroll.y, 0);
931 public DataRow GetPrevRow()
937 for(row = prev; row && !row.collapsed && row.subRows.last; row = row.subRows.last);
944 public DataRow GetNextRow()
948 if(subRows.first && !collapsed)
952 for(row = this; row; row = row.parent)
954 if(row.next) { row = row.next; break; }
960 private DataRow GetLastRow()
963 while(row && !row.collapsed && row.subRows.last)
964 row = row.subRows.last;
971 SelectedFlag selectedFlag;
982 public class ListBox : CommonControl
984 hasVertScroll = true;
985 // background = white;
987 snapVertScroll = true;
989 class_property(icon) = "<:ecere>controls/listBox.png";
993 property bool freeSelect { property_category $"Behavior" set { style.freeSelect = value; } get { return style.freeSelect; } };
994 property DataRow currentRow { property_category $"Private" /*"Behavior"*/ set { if(this) SetCurrentRow(value, false); } get { return this ? currentRow : null; } };
995 property DataField currentField
997 get { return currentField; }
998 // TODO: Document what this does
1001 currentField = value;
1002 HideEditBox(true, true, false);
1003 if(value && value.editable)
1004 PopupEditBox(currentField, false);
1008 property int rowHeight
1010 property_category $"Appearance"
1011 isset { return style.heightSet; }
1016 style.heightSet = true;
1018 SetScrollLineStep(8, value);
1022 style.heightSet = false;
1027 get { return this ? rowHeight : 0; }
1029 property Seconds typingTimeout
1031 property_category $"Behavior"
1034 typedString[0] = '\0';
1035 typingTimer.delay = value;
1036 typingTimeOut = value;
1038 get { return typingTimeOut; }
1040 property bool moveRows { property_category $"Behavior" set { style.moveRows = value; } get { return style.moveRows; } };
1041 property bool moveFields { property_category $"Behavior" set { style.moveFields = value; } get { return style.moveFields; } };
1042 property bool resizable { property_category $"Behavior" set { style.resizable = value; } get { return style.resizable; } };
1043 property bool autoScroll { property_category $"Behavior" set { style.autoScroll = value; } get { return style.autoScroll; } };
1044 property bool alwaysHighLight { property_category $"Appearance" set { style.alwaysHL = value; } get { return style.alwaysHL; } };
1045 property bool hasClearHeader { property_category $"Appearance" set { style.clearHeader = value; if(value) property::hasHeader = true; } get { return style.clearHeader; } };
1046 property bool hasHeader
1048 property_category $"Appearance"
1051 if(value && !style.header)
1057 bevel = !guiApp.textMode && !style.clearHeader;
1058 dontScrollVert = true;
1061 NotifyPushed = HeaderPushed;
1062 NotifyClicked = HeaderClicked;
1063 NotifyDoubleClick = HeaderDoubleClicked;
1064 NotifyReleased = HeaderReleased;
1065 NotifyMouseMove = HeaderMouseMove;
1069 endBevel.visible = false;
1071 style.header = value;
1073 get { return style.header; }
1075 property bool multiSelect { property_category $"Behavior" set { style.multiSelect = value; } get { return style.multiSelect; } };
1076 property bool alwaysEdit { property_category $"Behavior" set { style.alwaysEdit = value; } get { return style.alwaysEdit; } };
1077 property bool fullRowSelect { property_category $"Appearance" set { style.fullRowSelect = value; } get { return style.fullRowSelect; } };
1078 property bool collapseControl { property_category $"Appearance" set { style.collapse = value; } get { return style.collapse; } };
1079 property bool treeBranches { property_category $"Appearance" set { style.treeBranch = value; } get { return style.treeBranch; } };
1080 property bool rootCollapseButton { property_category $"Appearance" set { style.rootCollapse = value; } get { return style.rootCollapse; } };
1081 property bool sortable { property_category $"Behavior" set { style.sortable = value; } get { return style.sortable; } };
1082 property bool noDragging { property_category $"Behavior" set { style.noDragging = value; } get { return style.noDragging; } };
1083 property bool fillLastField
1085 property_category $"Behavior"
1088 style.fillLastField = value;
1090 get { return style.fillLastField; }
1092 property int numSelections
1096 int numSelections = 0;
1097 if(this && style.multiSelect)
1100 for(row = rows.first; row; row = row.GetNextRow())
1101 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
1104 return numSelections;
1107 property int currentIndex
1109 get { return currentRow ? currentRow.index : -1; }
1111 property DataRow lastRow { get { return this ? rows.last : null; } };
1112 property DataRow firstRow { get { return this ? rows.first : null; } };
1113 property int rowCount { get { return rowCount; } };
1114 property DataField firstField { get { return this ? fields.first : null; } };
1115 property Color selectionColor { set { selectionColor = value; } get { return selectionColor; } isset { return selectionColor ? true : false; } };
1116 property Color selectionText { set { selectionText = value; } get { return selectionText; } isset { return selectionText ? true : false; } };
1117 property Color stippleColor { set { stippleColor = value; } get { return stippleColor; } };
1118 property bool expandOnAdd { set { style.expandOnAdd = value; } get { return style.expandOnAdd; } };
1121 virtual bool Window::NotifySelect(ListBox listBox, DataRow row, Modifiers mods);
1122 virtual bool Window::NotifyHighlight(ListBox listBox, DataRow row, Modifiers mods);
1123 virtual bool Window::NotifyReclick(ListBox listBox, DataRow row, Modifiers mods);
1124 virtual bool Window::NotifySort(ListBox listBox, DataField field, Modifiers mods);
1125 virtual bool Window::NotifyChanged(ListBox listBox, DataRow row);
1126 virtual bool Window::NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch);
1127 virtual bool Window::NotifyEdited(ListBox listBox, DataRow row);
1128 virtual bool Window::NotifyEditDone(ListBox listBox, DataRow row);
1129 virtual bool Window::NotifyMovedField(ListBox listBox, DataField field, Modifiers mods);
1130 virtual bool Window::NotifyMove(ListBox listBox, DataRow row, Modifiers mods);
1131 virtual bool Window::NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods);
1132 virtual bool Window::NotifyRightClick(ListBox listBox, int x, int y, Modifiers mods);
1133 virtual bool Window::NotifyResized(ListBox listBox, DataField field, Modifiers mods);
1134 virtual bool Window::NotifyCollapse(ListBox listBox, DataRow row, bool collapsed);
1135 virtual bool Window::NotifyKeyHit(ListBox listBox, DataRow row, Key key, unichar ch);
1136 virtual bool Window::NotifyModified(ListBox listBox, DataRow row);
1137 virtual bool Window::NotifyEditing(ListBox listBox, DataRow row);
1138 virtual void Window::NotifyMoved(ListBox listBox, DataRow row, Modifiers mods);
1141 private void CheckConsistency()
1146 for(r = rows.first; r; r = r.GetNextRow())
1148 if(r.index != index++)
1156 void AddField(DataField addedField)
1161 if(fields.first && ((DataField)fields.first).defaultField)
1163 DataField defaultField = fields.first;
1164 defaultField.Free();
1165 delete defaultField;
1169 addedField = DataField { };
1173 addedField.listBox = this;
1174 fields.Add(addedField);
1176 addedField.sortOrder = 1;
1177 addedField.index = numFields;
1181 addedField.headButton.Destroy(0);
1182 delete addedField.headButton;
1183 addedField.headButton = Button
1188 dontScrollVert = true;
1189 id = (int64)(intptr)addedField;
1190 text = addedField.header;
1191 bevel = (!guiApp.textMode && !style.clearHeader);
1193 alignment = addedField.alignment;
1194 NotifyPushed = HeaderPushed;
1195 NotifyClicked = HeaderClicked;
1196 NotifyDoubleClick = HeaderDoubleClicked;
1197 NotifyReleased = HeaderReleased;
1198 NotifyMouseMove = HeaderMouseMove;
1200 incref addedField.headButton;
1201 addedField.headButton.Create();
1204 addedField.headButton.background = Color { 0, 170, 0 };
1210 for(row = rows.first; row; )
1212 int size = (field.dataType && field.dataType.typeSize) ?
1213 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1214 ListBoxCell cell = (ListBoxCell)new0 byte[size];
1215 row.cells.Add(cell);
1216 FillBytes(cell.data, 0, size - (uint)(uintptr)&((ListBoxCell)0).data);
1219 if(row.subRows.first)
1220 row = row.subRows.first;
1223 for(; row; row = row.parent)
1225 if(row.next) { row = row.next; break; }
1230 OnResize(clientSize.w, clientSize.h);
1239 Clear(); // Ensure data is cleared first
1240 while((field = fields.first))
1245 endBevel.visible = false;
1250 void RemoveField(DataField field)
1256 int index = field.index;
1259 if(sortField == field)
1262 for(row = rows.first; row; )
1267 for(cell = row.cells.first, c = 0; c < index && cell; c++, cell = cell.next);
1268 if(cell && index == c)
1272 // TOCHECK: Is this check good? Will need incref/decref sometime?
1273 if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
1275 if(cell.data[0] && field.freeData)
1276 ((void (*)(void *, void *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnFree])(field.dataType, cell.data[0]);
1279 ((void (*)(void *, void *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnFree])(field.dataType, cell.data);
1282 row.cells.Remove(cell);
1286 if(row.subRows.first)
1287 row = row.subRows.first;
1290 for(; row; row = row.parent)
1292 if(row.next) { row = row.next; break; }
1301 endBevel.visible = false;
1305 DataRow AddRowNone()
1307 DataRow row { noneRow = true };
1314 rows.Insert(null, row);
1317 for(search = row.GetNextRow(); search; search = search.GetNextRow())
1323 firstRowShown = row;
1327 (rowCount * rowHeight) +
1328 ((style.header) ? rowHeight : 0) -
1329 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1330 if(style.autoScroll)
1331 SetScrollPosition(0, MAXINT - rowHeight);
1332 modifiedDocument = true;
1351 // Find very last row
1354 for(lastRow = rows.last; lastRow && !lastRow.collapsed && lastRow.subRows.last; lastRow = lastRow.subRows.last);
1355 row.index = lastRow ? (lastRow.index + 1) : 0;
1363 for(c = 0; c<fields.count; c++)
1365 for(field = fields.first; field; field = field.next)
1366 if((int)field.index == c)
1370 int size = (field.dataType && field.dataType.typeSize) ?
1371 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1372 ListBoxCell cell = (ListBoxCell) new0 byte[size];
1373 row.cells.Add(cell);
1374 FillBytes(cell.data, 0, size - (uint)(uintptr)&((ListBoxCell)0).data);
1381 firstRowShown = row;
1387 (rowCount * rowHeight) +
1388 ((style.header) ? rowHeight : 0) -
1389 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1390 if(style.autoScroll)
1391 SetScrollPosition(0, MAXINT - rowHeight);
1392 modifiedDocument = true;
1403 DataRow AddRowAfter(DataRow after)
1415 if(after && after.subRows.first && !after.collapsed)
1417 for(search = after.subRows.last; !search.collapsed && search.subRows.last; )
1418 search = search.subRows.last;
1419 row.index = search.index + 1;
1422 row.index = after ? (after.index + 1) : 0;
1423 rows.Insert(after, row);
1426 for(search = row.GetNextRow(); search; search = search.GetNextRow())
1431 for(c = 0; c<fields.count; c++)
1433 for(field = fields.first; field; field = field.next)
1434 if((int)field.index == c)
1438 int size = (field.dataType && field.dataType.typeSize) ?
1439 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1440 ListBoxCell cell = (ListBoxCell) new0 byte[size];
1441 row.cells.Add(cell);
1442 FillBytes(cell.data, 0, size - (uint)(uintptr)&((ListBoxCell)0).data);
1446 if(!firstRowShown || !after)
1448 firstRowShown = row;
1453 (rowCount * rowHeight) +
1454 ((style.header) ? rowHeight : 0) -
1455 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1456 if(style.autoScroll)
1457 SetScrollPosition(0, MAXINT - rowHeight);
1458 modifiedDocument = true;
1468 DataRow AddStringf(const char * format, ...)
1474 char string[MAX_F_STRING];
1477 va_start(args, format);
1478 vsnprintf(string, sizeof(string), format ? format : "", args);
1479 string[sizeof(string)-1] = 0;
1483 row.SetData(fields.first, string);
1489 DataRow AddString(const char * string)
1495 row.SetData(fields.first, string);
1501 void SelectRow(DataRow row)
1503 SetCurrentRow(row, true);
1506 void DeleteRow(DataRow row)
1508 if(!row) row = currentRow;
1511 DataRow sub, next, search;
1512 // Trying to move this here (Messed up deleting watches)
1513 //HideEditBox(false, false, true);
1516 for(sub = row.subRows.first; sub; sub = next)
1522 if(row.parent.IsExpanded())
1524 for(search = row.GetNextRow(); search; search = search.GetNextRow())
1529 HideEditBox(false, false, true);
1531 if(row == clickedRow)
1533 clickedRow = row.GetNextRow();
1535 clickedRow = row.GetPrevRow();
1538 if(row == currentRow)
1540 DataRow newCurrentRow = row.GetNextRow();
1542 newCurrentRow = row.GetPrevRow();
1543 SetCurrentRow(newCurrentRow, true);
1546 if(row == firstRowShown)
1548 firstRowShown = row.GetPrevRow();
1550 firstRowShown = row.GetNextRow();
1553 (row.parent ? row.parent.subRows: rows).Remove(row);
1556 //HideEditBox(false, false, true);
1560 (rowCount * rowHeight) +
1561 ((style.header) ? rowHeight : 0) -
1562 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1564 modifiedDocument = true;
1573 DataRow FindRow(int64 tag)
1578 for(row = rows.first; row; row = row.next)
1580 if(!row.noneRow && row.tag == tag)
1588 DataRow FindString(const char * searchedString)
1591 bool checkNextField = true;
1593 for(field = fields.first; field; field = field.next)
1595 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1598 for(row = rows.first; row; row = row.GetNextRow())
1602 void * data = row.GetData(field);
1603 char tempString[1024] = "";
1604 bool needClass = false;
1605 const char * string = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, data, tempString, null, &needClass);
1607 if(string && string[0])
1608 checkNextField = false;
1609 if(string && string[0] && !strcmp(string, searchedString))
1614 if(!checkNextField) break;
1619 DataRow FindSubString(const char * subString)
1622 bool checkNextField = true;
1623 int len = subString ? strlen(subString) : 0;
1627 for(field = fields.first; field; field = field.next)
1629 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1632 for(row = rows.first; row; row = row.GetNextRow())
1636 void * data = row.GetData(field);
1637 char tempString[1024] = "";
1638 bool needClass = false;
1639 const char * string = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, data, tempString, null, &needClass);
1641 if(string && string[0])
1642 checkNextField = false;
1643 if(string && string[0] && !strncmp(string, subString, len))
1648 if(!checkNextField) break;
1654 DataRow FindSubStringi(const char * subString)
1657 bool checkNextField = true;
1658 int len = subString ? strlen(subString) : 0;
1659 DataRow result = null;
1660 const char * bestResult = null;
1665 for(field = fields.first; field; field = field.next)
1667 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1670 for(row = rows.first; row; row = row.GetNextRow())
1674 void * data = row.GetData(field);
1675 char tempString[1024] = "";
1676 bool needClass = false;
1677 const char * string = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, data, tempString, null, &needClass);
1679 if(string && string[0])
1680 checkNextField = false;
1681 if(string && string[0])
1683 int stringLen = strlen(string);
1685 if(!strnicmp(string, subString, Min(len, stringLen)))
1687 if(bestLen < Min(len, stringLen))
1689 if(!bestResult || strcmpi(string, bestResult) < 0)
1691 bestLen = Min(len, stringLen);
1692 bestResult = string;
1700 if(!checkNextField) break;
1706 DataRow FindSubStringAfter(DataRow after, const char * subString)
1709 bool checkNextField = true;
1710 int len = subString ? strlen(subString) : 0;
1714 for(field = fields.first; field; field = field.next)
1716 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1719 for(row = after.GetNextRow(); row && row != after; row = row.GetNextRow(), (!row) ? (row = rows.first) : null)
1723 void * data = row.GetData(field);
1724 char tempString[1024] = "";
1725 bool needClass = false;
1726 const char * string = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, data, tempString, null, &needClass);
1728 if(string && string[0])
1729 checkNextField = false;
1730 if(string && string[0] && !strncmp(string, subString, len))
1735 if(!checkNextField) break;
1741 DataRow FindSubRow(int64 tag)
1747 for(row = rows.first; row; row = row.next)
1749 if(!row.noneRow && row.tag == tag)
1751 if(!row.noneRow && row.subRows.first)
1753 DataRow subRow = row.FindSubRow(tag);
1767 Window master = this.master;
1769 HideEditBox(false, true, false);
1770 editData.Destroy(0);
1772 firstRowShown = currentRow = null;
1777 if(style.freeSelect)
1778 NotifyHighlight(master, this, currentRow ? currentRow : null, 0);
1780 NotifySelect(master, this, currentRow ? currentRow : null, 0);
1783 if(style.alwaysEdit && currentRow)
1784 currentRow.Edit(currentField);
1791 (rowCount * rowHeight) +
1792 ((style.header) ? rowHeight : 0) -
1793 ((rowHeight && !((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1798 void Sort(DataField field, int order)
1803 int headerSize = ((style.header) ? rowHeight : 0);
1804 int height = clientSize.h + 1 - headerSize;
1806 if(!field) field = fields.first;
1808 field.sortOrder = order ? order : 1;
1809 rows.Sort(DataRow::Compare, field);
1811 for(search = rows.first; search; search = search.next)
1812 search._SortSubRows(field, order);
1816 for(search = rows.first; search; search = search.GetNextRow())
1817 search.index = index++;
1820 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
1821 SetScrollPosition(scroll.x, currentRow.index * rowHeight - height + rowHeight);
1822 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
1823 SetScrollPosition(scroll.x, currentRow ? currentRow.index * rowHeight : 0);
1825 OnVScroll(0, scroll.y, 0);
1827 // SetScrollPosition(0, scroll.y);
1832 void StopEditing(bool save)
1834 HideEditBox(save, false, true);
1837 void GetMultiSelection(OldList list)
1840 if(this && style.multiSelect)
1844 for(row = rows.first; row; row = row.GetNextRow())
1846 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
1848 list.Add(OldLink { data = row });
1854 // Convenience Current Row Methods
1855 void * SetData(DataField field, any_object data)
1857 return currentRow.SetData(field, data);
1860 any_object GetData(DataField field)
1862 return (void *)currentRow.GetData(field);
1867 return currentRow ? currentRow.tag : 0;
1873 DataField defaultField { };
1874 rows.offset = (uint)(uintptr)&((DataRow)0).prev;
1875 fields.offset = (uint)(uintptr)&((DataField)0).prev;
1876 style.fullRowSelect = true;
1877 style.fillLastField = true;
1878 style.expandOnAdd = true;
1879 typingTimeOut = 0.5;
1880 rowHeight = 16; // Stuff depending on creation and default property checking
1883 defaultField.defaultField = true;
1885 AddField(defaultField);
1887 typedString = new char[1];
1888 typedString[0] = '\0';
1903 while((field = fields.first))
1905 // fields.Remove(field);
1915 while((row = rows.first))
1922 ListBoxCell GetCell(DataRow * row, DataField * field)
1924 ListBoxCell cell = null;
1925 if(!*row) *row = currentRow;
1928 if(!*field) *field = this ? currentField : null;
1931 for(*field = fields.first; (*field).index != 0; *field = (*field).next);
1936 if(field->listBox == this)
1938 for(index = 0, cell = (*row).cells.first; cell && index != (*field).index; index++, cell = cell.next);
1945 void HideEditBox(bool save, bool alwaysStopEdit, bool repositionOnly)
1947 if(editData && editData.visible)
1950 editData.SaveData();
1952 editData.visible = false;
1953 NotifyEditDone(master, this, currentRow);
1955 // ENSURE DATA BOX IS NOT VISIBLE
1956 editData.visible = false;
1958 if(style.alwaysEdit && !alwaysStopEdit)
1961 int height = rowHeight - (style.alwaysEdit ? 1 : 0);
1962 int y = currentRow.index * rowHeight + (style.header ? rowHeight : 0);
1963 int x = currentField.x;
1964 int width = (!currentField.next && style.fillLastField && (!hasHorzScroll || clientSize.w - currentField.x > currentField.width + EXTRA_SPACE)) ?
1965 clientSize.w - currentField.x : (currentField.width + EXTRA_SPACE);
1967 if(!style.alwaysEdit)
1969 editData.position = { x, y };
1970 editData.size = { width, height };
1974 editData.position = { x, y - editData.clientStart.y };
1975 editData.size = { width, height + editData.clientStart.y * 2 };
1977 editData.visible = true;
1978 if(style.alwaysEdit)
1979 editData.Deactivate();
1981 PopupEditBox(currentField, repositionOnly);
1985 currentField = null;*/
1990 static bool DebugFindRow(DataRow parent, DataRow row)
1994 for(r = parent.subRows.first; r; r = r.next)
2001 if(DebugFindRow(r, row))
2011 void SetCurrentRow(DataRow row, bool notify)
2018 for(r = rows.first; r; r = r.next)
2025 if(DebugFindRow(r, row))
2032 PrintLn("ERROR: Setting currentRow to a row not found in ListBox!!");
2035 if(this && (currentRow != row || (currentRow && currentRow.selectedFlag == unselected)))
2037 int headerSize = ((style.header) ? rowHeight : 0);
2038 int height = clientSize.h + 1 - headerSize;
2040 // true: destroy edit box
2041 HideEditBox(true, true, false);
2043 if(!(style.multiSelect) && currentRow)
2044 currentRow.selectedFlag = unselected;
2048 if(style.multiSelect)
2052 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
2053 selRow.selectedFlag = unselected;
2055 currentRow.selectedFlag = selected;
2060 currentRow.selectedFlag = selected;
2062 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
2063 SetScrollPosition(scroll.x,
2064 currentRow.index * rowHeight - height + rowHeight);
2065 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
2067 int line = currentRow ? currentRow.index * rowHeight : 0;
2068 //SNAPUP(line, rowHeight);
2069 SetScrollPosition(scroll.x, line);
2074 Window master = this.master;
2077 if(style.freeSelect && visible)
2078 NotifyHighlight(master, this, currentRow ? currentRow : null, 0);
2080 NotifySelect(master, this, currentRow ? currentRow : null, 0);
2081 if(style.alwaysEdit && currentRow)
2082 currentRow.Edit(currentField);
2090 void RepositionFieldEditor()
2092 if(editData && editData.visible)
2094 int height = rowHeight - (style.alwaysEdit ? 1 : 0);
2096 int y = currentRow.index * rowHeight + (style.header ? rowHeight : 0);
2100 if(style.collapse && !(style.treeBranch))
2102 for(field = fields.first; field; field = field.next)
2104 width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2105 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2106 if(field == currentField) break;
2109 if(!style.alwaysEdit)
2111 editData.position = { x, y - editData.clientStart.y };
2112 editData.size = { width, height + editData.clientStart.y * 2 };
2116 editData.position = { x, y };
2117 editData.size = { width, height };
2122 void PopupEditBox(DataField whichField, bool repositionOnly)
2124 if((!editData || !editData.visible || currentField != whichField) && currentRow)
2126 // true: destroy edit box
2127 HideEditBox(true, true, false);
2130 int height = rowHeight - (style.alwaysEdit ? 1 : 0);
2132 int y = currentRow.index * rowHeight + (style.header ? rowHeight : 0);
2134 //void * data = currentRow.GetData(whichField);
2139 if(style.collapse && !(style.treeBranch))
2142 for(field = fields.first; field; field = field.next)
2144 width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2145 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2146 if(field == whichField) break;
2150 currentField = whichField;
2151 cell = GetCell(&row, ¤tField);
2158 background = dataBoxBackground;
2159 foreground = dataBoxForeground;
2161 bool NotifyChanged(DataBox dataBox, bool closingDropDown)
2164 DataField field = null;
2165 ListBoxCell cell = GetCell(&row, &field);
2169 modifiedDocument = true;
2171 NotifyChanged(master, this, currentRow);
2176 bool NotifyModified()
2178 //DataRow row = null;
2179 //DataField field = null;
2180 //ListBoxCell cell = GetCell(&row, &field);
2181 //cell.isSet = true;
2182 modifiedDocument = true;
2184 NotifyModified(master, this, currentRow);
2188 bool OnKeyDown(Key key, unichar ch)
2190 bool result = DataBox::OnKeyDown(key, ch);
2191 if(visible && active) // Added this check here, because we will not use enter/escape otherwise, and lose DataBox's result
2193 if((SmartKey)key == enter || (SmartKey)key == escape)
2202 editData.Destroy(0);
2203 editData.type = whichField.dataType;
2204 editData.fieldData = whichField.userData;
2205 editData.borderStyle = style.alwaysEdit ? 0 : deep;
2206 editData.data = cell ? cell.data : null;
2209 // Might not really need this anymore...
2210 NotifyEditing(master, this, currentRow);
2213 if(!style.alwaysEdit)
2215 editData.position = { x, y - editData.clientStart.y };
2216 editData.size = { width, height + editData.clientStart.y * 2 };
2220 editData.position = { x, y };
2221 editData.size = { width, height };
2225 editData.visible = true;
2227 if(style.alwaysEdit)
2228 editData.Deactivate();
2230 // MOVED THIS HIGHER FOR DATALIST EDITOR
2232 // Might not really need this anymore...
2233 NotifyEdited(master, this, currentRow);
2238 void OnRedraw(Surface surface)
2241 int y = (style.header) ? rowHeight : 0;
2242 bool isActive = active;
2243 Font font = fontObject;
2244 Font boldFont = this.boldFont.font;
2247 if(style.alwaysEdit && style.fullRowSelect)
2250 int y = (style.header) ? rowHeight : 0;
2251 int x = -scroll.x - 1;// + EXTRA_SPACE;// / 2 - 1;
2252 int w = clientSize.w;
2253 int h = clientSize.h;
2257 // Fill out indent column
2258 if(style.collapse && !(style.treeBranch) && (style.header || rows.first))
2261 surface.SetBackground(formColor);
2262 surface.Area(-scroll.x, 0, x, clientSize.h);
2265 surface.SetForeground(formColor);
2266 for(row = firstRowShown; row; row = row.GetNextRow())
2269 surface.HLine(x + 1, w-1, y-1);
2275 for(field = fields.first; field; field = field.next)
2277 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2278 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2279 if(field.prev && y > 0)
2280 surface.VLine(0, y-1, x);
2285 surface.foreground = this.foreground;
2286 surface.TextOpacity(false);
2288 // Draw the tree branches
2289 if(style.treeBranch)
2291 int y = -scroll.y + ((style.header) ? rowHeight : 0);
2292 surface.LineStipple(0x5555);
2293 surface.SetForeground(branchesColor);
2294 for(row = rows.first; row; row = row.GetNextRow() )
2296 int x = -scroll.x + EXTRA_SPACE / 2-1;
2297 int rowStart = -scroll.x;
2302 for(parent = row.parent; parent; parent = parent.parent)
2303 if(!parent.header) indent += 20;
2304 if(style.rootCollapse) indent += 20;
2306 plusIndent = (style.treeBranch) ? (indent - 20 + 4) : indent;
2311 if(row.subRows.first)
2314 int y1 = y + PLUSY + 4;
2318 for(child = row.collapsed ? null : row.subRows.first; child && child != row; )
2321 if(child.subRows.first && !child.collapsed && child != row.subRows.last)
2322 child = child.subRows.first;
2327 for(; child && child != row; child = child.parent)
2337 y2 = y + numRows * rowHeight + PLUSY + 4;
2338 surface.VLine(y1, y2, rowStart + plusIndent + 7 + 20);
2340 surface.HLine(rowStart + plusIndent + 7, rowStart + indent, y + PLUSY + 4);
2343 if(y >= clientSize.h)
2346 // Root Vertical Lines
2347 if(style.rootCollapse && rows.first)
2352 y = -scroll.y + ((style.header) ? rowHeight : 0);
2354 for(child = rows.first; child && child != rows.last; )
2357 if(child.subRows.first && !child.collapsed && child != rows.last)
2358 child = child.subRows.first;
2363 for(; child; child = child.parent)
2373 y2 = y + numRows * rowHeight + PLUSY + 4;
2374 surface.VLine(y1, y2, -scroll.x + 11);
2376 surface.LineStipple(0);
2379 for(row = firstRowShown; row; row = row.GetNextRow() )
2381 int x = -scroll.x + EXTRA_SPACE / 2-1;
2384 Color foreground = this.foreground /*black*/, background = this.background /*white*/;
2385 DataDisplayFlags dataDisplayFlags = 0;
2386 int rowStart = -scroll.x;
2389 Bitmap icon = row.icon ? row.icon.bitmap : null;
2390 int collapseRowStart = 0;
2391 bool lastWasHeader = row.header;
2393 for(parent = row.parent; parent; parent = parent.parent)
2395 if(!parent.header || lastWasHeader)
2397 if(style.treeBranch)
2403 if(style.rootCollapse) indent += 20;
2406 dataDisplayFlags.fullRow = style.fullRowSelect;
2407 dataDisplayFlags.active = isActive;
2408 dataDisplayFlags.header = row.header;
2413 collapseRowStart = rowStart;
2415 if(!(style.treeBranch))
2422 if(style.multiSelect)
2424 dataDisplayFlags.selected = row.selectedFlag == selected || row.selectedFlag == tempSelected;
2425 dataDisplayFlags.current = row == currentRow || (!currentRow && row == firstRowShown);
2429 dataDisplayFlags.selected = row.selectedFlag == selected || row.selectedFlag == tempSelected;
2430 dataDisplayFlags.current = row == currentRow || (!currentRow && row == firstRowShown);
2432 if(row == currentRow)
2434 dataDisplayFlags.current = true;
2435 dataDisplayFlags.selectedFlag = true;
2437 else if(!currentRow && row == firstRowShown)
2439 dataDisplayFlags.current = true;
2443 surface.TextOpacity(true);
2445 background = this.background;
2446 foreground = this.foreground;
2448 // Draw the current row background
2451 Color colors[] = { formColor, azure, mistyRose, linen, floralWhite, lavender, lavenderBlush, lemonChiffon };
2454 while((p = p.parent)) level++;
2455 background = colors[level % (sizeof(colors)/sizeof(colors[0]))];
2456 surface.SetBackground(background);
2457 surface.Area(rowStart, y, clientSize.w, (y + rowHeight) - 1);
2458 foreground = branchesColor;
2460 else if(dataDisplayFlags.selected)
2462 if(dataDisplayFlags.selected && (isActive || style.alwaysHL || (style.alwaysEdit && style.fullRowSelect)))
2464 if(!isActive && style.alwaysEdit)
2465 background = formColor;
2467 background = selectionColor ? selectionColor : SELECTION_COLOR;
2468 if(style.fullRowSelect)
2470 int offset = (style.alwaysEdit) ? 2 : 1;
2471 surface.SetBackground(background);
2472 surface.Area(rowStart, y, clientSize.w, (y + rowHeight) - offset);
2474 if(isActive || !(style.alwaysEdit))
2475 foreground = selectionText ? selectionText : SELECTION_TEXT;
2477 foreground = branchesColor;
2483 surface.Blit(icon, x + (20 - icon.width) /2,y + 2,0,0, icon.width, icon.height);
2489 int width = clientSize.w;
2491 dataDisplayFlags.firstField = true;
2492 clip.left = x - EXTRA_SPACE / 2+1;
2494 clip.right = x + width - EXTRA_SPACE/2 - 0;
2495 clip.bottom = y + rowHeight - 1;
2496 surface.Clip(&clip);
2498 surface.TextFont(font);
2500 surface.SetForeground(foreground);
2501 surface.SetBackground(background);
2503 ((void (*)(void *, const void *, void *, int, int, int, void *, uint, uint))(void *)class(String)._vTbl[__ecereVMethodID_class_OnDisplay])(class(String), "(none)", surface, x, y - 1 + (rowHeight - fontH)/2, width - EXTRA_SPACE/2, null, Alignment::left, dataDisplayFlags);
2507 if(opacity < 1) surface.TextOpacity(false);
2509 for(field = fields.first; field; field = field.next)
2512 int width = ((!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) || row.header) ?
2513 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2515 // Box clip = { x, y+1, x + field.width - EXTRA_SPACE - 1, y + rowHeight - 2 };
2518 //width -= EXTRA_SPACE;
2520 if(!field.prev) width -= indent;
2523 dataDisplayFlags.firstField = field.prev ? false : true;
2525 if(!dataDisplayFlags.firstField && !dataDisplayFlags.fullRow)
2527 background = this.background;
2528 foreground = this.foreground;
2531 if(!isActive && dataDisplayFlags.selected && style.alwaysEdit && field.editable && opacity)
2534 surface.SetBackground(background);
2535 surface.Area(x-3, y, x+width-1, y + rowHeight-2);
2538 clip.left = x - EXTRA_SPACE / 2+1;
2540 clip.right = x + width - EXTRA_SPACE/2 - 0;
2541 clip.bottom = y + rowHeight - 1;
2542 surface.Clip(&clip);
2544 for(index = 0, cell = row.cells.first; cell && index != field.index; index++, cell = cell.next);
2545 // Should always be as many cells in the row as fields in the listbox
2546 if(cell && cell.isSet && field.dataType)
2549 surface.TextFont(boldFont);
2551 surface.TextFont(font);
2553 surface.SetForeground(foreground);
2554 surface.SetBackground(background);
2556 if(field.dataType.type == noHeadClass || field.dataType.type == normalClass)
2557 ((void (*)(void *, void *, void *, int, int, int, void *, uint, uint))(void *)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);
2559 ((void (*)(void *, void *, void *, int, int, int, void *, uint, uint))(void *)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);
2562 if(!isActive && dataDisplayFlags.selected && style.alwaysEdit && field.editable)
2563 background = formColor;
2565 if(!dataDisplayFlags.firstField && !dataDisplayFlags.fullRow)
2567 background = formColor;
2568 foreground = this.background;
2572 // surface.WriteTextf(x + 100, y, "ix: %d", row.index);
2575 x += width;// + EXTRA_SPACE;
2577 if(row.header) break;
2583 int plusIndent = (style.treeBranch) ? (indent - 20 + 4) : indent;
2585 if(row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)))
2587 surface.SetForeground(row.header ? headerCollapseForeground : this.foreground);
2588 surface.Rectangle(collapseRowStart + 3 + plusIndent, y + PLUSY, collapseRowStart + 11 + plusIndent, y + PLUSY + 8);
2590 surface.SetBackground(row.header ? (formColor) : (this.background)); //white
2591 surface.Area(collapseRowStart + 4 + plusIndent, y + PLUSY + 1, collapseRowStart + 10 + plusIndent, y + PLUSY + 7);
2593 surface.HLine(collapseRowStart + 5 + plusIndent, collapseRowStart + 9 + plusIndent, y+PLUSY+4);
2595 surface.VLine(y + PLUSY + 2, y + PLUSY + 6, collapseRowStart + 7 + plusIndent);
2600 // Draw the current row stipple
2601 if(style.fullRowSelect && !(style.alwaysEdit) && (dataDisplayFlags.current) && isActive)
2606 surface.LineStipple(0x5555);
2607 if(dataDisplayFlags.selected)
2608 surface.SetForeground(stippleColor);
2610 surface.SetForeground(this.foreground);
2613 surface.SetForeground(selectionColor ? selectionColor : SELECTION_COLOR);
2614 surface.Rectangle(0, y, clientSize.w-1, (y + rowHeight) - 1);
2615 surface.LineStipple(0);
2619 if(y >= clientSize.h)
2622 if(firstRowShown) surface.Clip(null);
2623 if(dragRow && dropIndex != -1)
2628 if(!style.multiSelect && currentRow.index < dropIndex)
2630 surface.DrawingChar(223);
2632 y = style.header ? rowHeight : 0;
2633 y += ix * rowHeight - scroll.y;
2635 surface.SetForeground(Color { 85, 85, 255 });
2636 surface.HLine(0, clientSize.w-1, y);
2637 surface.HLine(0, clientSize.w-1, y + 1);
2641 void OnDrawOverChildren(Surface surface)
2643 if(draggingField && dropField)
2645 int position = dropField.x;
2646 if(draggingField.x < position)
2647 position += dropField.width + EXTRA_SPACE;
2649 surface.SetForeground(Color { 85, 85, 255 });
2650 surface.VLine(0, rowHeight - 1, position - scroll.x - 2);
2651 surface.VLine(0, rowHeight - 1, position - scroll.x);
2653 if(sortField && !style.clearHeader && style.header)
2655 DataField field = sortField;
2656 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2657 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2660 surface.TextExtent(field.header, strlen(field.header), &tw, &th);
2661 if(tw < width - EXTRA_SPACE)
2663 bool up = field.sortOrder == 1;
2667 field.x + 2 - scroll.x, 0,
2668 field.x + width + EXTRA_SPACE - 1 - scroll.x, rowHeight
2670 surface.Clip(&clip);
2671 if(field.alignment == left || field.alignment == center)
2673 if(field.alignment == center)
2674 x = field.x + (width + EXTRA_SPACE - tw) / 2 + tw + EXTRA_SPACE + 4;
2676 x = field.x + tw + EXTRA_SPACE + 4;
2678 x = Min(x, field.x + width - 4);
2680 else if(field.alignment == right)
2682 x = field.x + width - tw - 2*EXTRA_SPACE - 4;
2683 x = Max(x, field.x + 2);
2689 // surface.SetForeground((wmenu.selectedFlag == item) ? white : black);
2690 // surface.WriteText(clientSize.w-8, y+(wmenu.rh - 8)/2, "\020", 1);
2696 surface.SetForeground(Color { 128,128,128 } );
2697 surface.DrawLine(x + 3, y, x, y + 5);
2698 surface.PutPixel(x + 1, y + 5);
2699 surface.PutPixel(x + 1, y + 3);
2700 surface.PutPixel(x + 2, y + 1);
2702 surface.SetForeground(white);
2703 surface.DrawLine(x + 4, y, x + 7, y + 5);
2704 surface.PutPixel(x + 6, y + 5);
2705 surface.PutPixel(x + 6, y + 3);
2706 surface.PutPixel(x + 5, y + 1);
2708 surface.DrawLine(x, y + 6, x + 7, y + 6);
2712 surface.SetForeground(Color { 128,128,128 });
2713 surface.DrawLine(x + 3, y+6, x, y+1);
2714 surface.PutPixel(x + 1, y+1);
2715 surface.PutPixel(x + 1, y+3);
2716 surface.PutPixel(x + 2, y+5);
2718 surface.SetForeground(white);
2719 surface.DrawLine(x + 4, y+6, x + 7, y+1);
2720 surface.PutPixel(x + 6, y+1);
2721 surface.PutPixel(x + 6, y+3);
2722 surface.PutPixel(x + 5, y+5);
2724 surface.DrawLine(x, y, x + 7, y);
2733 void OnResize(int w, int h)
2736 bool showEndBevel = false;
2738 if(style.collapse && !style.treeBranch)
2740 for(field = fields.first; field; field = field.next)
2742 int width = field.width + EXTRA_SPACE;
2750 (rowCount * rowHeight) +
2751 ((style.header) ? rowHeight : 0) -
2752 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
2754 for(field = fields.first; field; field = field.next)
2756 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2757 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2758 if(style.header && field.headButton)
2760 showEndBevel = true;
2763 field.headButton.position = { field.x, 0 };
2764 field.headButton.size = { width, rowHeight };
2765 field.headButton.visible = true;
2768 field.headButton.visible = false;
2772 if(!style.fillLastField && showEndBevel && endBevel)
2774 endBevel.position = { x, 0 };
2775 endBevel.size = { clientSize.w + 2 - x, rowHeight };
2776 endBevel.visible = true;
2779 endBevel.visible = false;
2781 if(style.alwaysEdit && editData && editData.visible)
2783 HideEditBox(true, false, true);
2785 else if(editData && editData.visible)
2786 RepositionFieldEditor();
2789 void AdaptToFieldWidth(DataField field, bool doScroll)
2791 OnResize(clientSize.w, clientSize.h);
2793 // Scroll appropriately
2796 if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x &&
2797 field.x >= field.x + field.width + EXTRA_SPACE - clientSize.w)
2799 SetScrollPosition(field.x + field.width + EXTRA_SPACE - clientSize.w, scroll.y);
2801 else if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x ||
2803 SetScrollPosition(field.x, scroll.y);
2808 bool HeaderPushed(Button control, int x, int y, Modifiers mods)
2810 DataField field = (DataField)(intptr)control.id;
2811 // false: dont destroy edit box
2812 HideEditBox(true, false, true);
2813 if(style.resizable && ((!field && x < RESIZE_BORDER && fields.last) ||
2814 (field && x < RESIZE_BORDER && field.prev) ||
2815 (field && x >= control.clientSize.w - RESIZE_BORDER)))
2818 field = fields.last;
2819 else if(x < RESIZE_BORDER && field.prev)
2822 if(field.fixed) return false;
2823 resizingField = field;
2824 resizeX = x + control.position.x;
2825 startWidth = field.width;
2826 oldX = x - scroll.x;
2831 if(field.fixed) return false;
2832 draggingField = field;
2833 if(style.moveFields)
2834 field.headButton.stayDown = true;
2835 else if(!style.sortable)
2843 bool HeaderMouseMove(Button control, int x, int y, Modifiers mods)
2848 DataField field = resizingField;
2850 x += control.position.x;
2852 // Tweak to prevent shrinking field if we're actually moving right
2853 if(x - scroll.x > oldX &&
2854 startWidth + x - resizeX < field.width)
2856 oldX = x - scroll.x;
2859 oldX = x - scroll.x;
2861 field.width = startWidth + x - resizeX;
2862 field.width = Max(field.width, - EXTRA_SPACE);
2864 AdaptToFieldWidth(field, true);
2866 else if(draggingField)
2868 x += control.position.x;
2869 if(style.moveFields)
2871 DataField field = fields.last;
2873 for(field = fields.first; field; field = field.next)
2875 fieldX += ((field.width || style.resizable) ?
2876 field.width : clientSize.w) + EXTRA_SPACE;
2880 if(draggingField == field)
2882 // Reset scroll position
2883 if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x &&
2884 field.x >= field.x + field.width + EXTRA_SPACE - clientSize.w)
2887 field.x + field.width + EXTRA_SPACE - clientSize.w,
2890 else if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x ||
2892 SetScrollPosition(field.x, scroll.y);
2895 if(dropField != field)
2900 int position = field.x;
2902 if(draggingField.x < position)
2904 position += field.width + EXTRA_SPACE - clientSize.w;
2905 if(position > scroll.x)
2906 SetScrollPosition(position, scroll.y);
2911 if(position < scroll.x)
2912 SetScrollPosition(position, scroll.y);
2915 movingFields = true;
2921 else if(style.resizable)
2923 DataField field = (DataField)(intptr)control.id;
2926 if(x < RESIZE_BORDER && field.prev)
2928 if(!field.prev.fixed)
2929 control.cursor = guiApp.GetCursor(sizeWE);
2931 else if(x >= control.clientSize.w - RESIZE_BORDER)
2932 control.cursor = guiApp.GetCursor(sizeWE);
2934 control.cursor = null;
2938 if(x < RESIZE_BORDER && fields.last)
2939 control.cursor = guiApp.GetCursor(sizeWE);
2941 control.cursor = null;
2947 bool HeaderReleased(Button control, int x, int y, Modifiers mods)
2951 NotifyResized(master, this, resizingField, mods);
2952 resizingField = null;
2959 if(style.moveFields)
2964 DataField switchField = fields.last;
2968 x += draggingField.x;
2969 for(field = fields.first; field; field = field.next)
2971 fieldX += ((field.width || style.resizable) ?
2972 field.width : clientSize.w) + EXTRA_SPACE;
2975 switchField = field;
2979 if(switchField && draggingField != switchField && dropField)
2981 for(field = fields.first; field; field = field.next)
2983 if(field == switchField || field == draggingField)
2987 // Switch field first: move before
2988 if(field == switchField)
2989 draggingField.Move(switchField.prev);
2990 // Dragged field first: move after
2992 draggingField.Move(switchField);
2994 NotifyMovedField(master, this, draggingField, mods);
2996 draggingField.headButton.stayDown = false;
3001 movingFields = false;
3003 draggingField = null;
3009 bool HeaderClicked(Button control, int x, int y, Modifiers mods)
3011 if(style.header && !dropField && style.sortable)
3013 DataField field = (DataField)(intptr)control.id;
3014 if(sortField == field)
3015 field.sortOrder *= -1;
3020 Sort(sortField, field.sortOrder);
3021 NotifySort(master, this, field, mods);
3027 bool HeaderDoubleClicked(Button control, int x, int y, Modifiers mods)
3031 DataField field = (DataField)(intptr)control.id;
3034 if(x < RESIZE_BORDER && field.prev)
3036 else if(x >= control.clientSize.w - RESIZE_BORDER);
3042 if(x < RESIZE_BORDER && fields.last)
3043 field = fields.last;
3055 if(style.freeSelect)
3060 rolledOver = dragging = false;
3067 bool OnLoadGraphics()
3069 display.FontExtent(fontObject, "W", 1, null, &fontH);
3070 if(!style.heightSet)
3072 rowHeight = Max(fontH + 2, 16) + (style.alwaysEdit ? 1 : 0);
3073 SetScrollLineStep(8, rowHeight);
3078 void OnApplyGraphics()
3080 SetScrollLineStep(8, rowHeight);
3084 for(field = fields.first; field; field = field.next)
3086 if(field.headButton)
3088 field.headButton.bevel = (!guiApp.textMode && !style.clearHeader);
3090 field.headButton.background = Color { 0, 170, 0 };
3094 OnResize(clientSize.w, clientSize.h);
3097 bool OnResizing(int *w, int *h)
3101 if(!initSize.w && (!anchor.left.type || !anchor.right.type) && !*w)
3106 Font font = fontObject;
3107 Font boldFont = this.boldFont.font;
3108 Display display = this.display;
3110 for(row = rows.first; row; row = row.GetNextRow())
3112 Bitmap icon = row.icon ? row.icon.bitmap : null;
3113 int x = -scroll.x + EXTRA_SPACE / 2-1;
3117 for(parent = row.parent; parent; parent = parent.parent)
3121 if(style.treeBranch)
3127 if(style.rootCollapse) indent += 20;
3129 if(style.collapse && !(style.treeBranch)) x += 15;
3133 // Compute the rows size
3134 for(field = fields.first; field; field = field.next)
3136 if(((style.resizable && (!(style.alwaysEdit) || field.next)) || field.width) && !row.header)
3137 x += field.width - (field.prev ? 0 : indent);
3142 for(index = 0, cell = row.cells.first; index != field.index; index++, cell = cell.next);
3144 // Should always be as many cells in the row as fields in the listbox
3145 if(cell && cell.isSet && field.dataType)
3147 static char tempString[4096];
3148 const char * string;
3150 if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
3151 string = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, cell.data[0], tempString, field.userData, null);
3153 string = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, cell.data, tempString, field.userData, null);
3155 if(!string) string = "";
3156 display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, &th);
3159 display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, &th);
3161 display.FontExtent(row.header ? boldFont : font, "", 0, &tw, &th);
3164 if(row.header) break;
3168 maxWidth = Max(maxWidth, x);
3174 *h = Min(maxShown, rowCount) * rowHeight;
3179 if(!*w) *w = rowHeight * 5;
3180 if(!*h) *h = rowHeight * 5;
3187 FontResource font = this.font;
3188 FontResource boldFont
3190 faceName = font.faceName, size = font.size, bold = true
3192 AddResource(boldFont);
3193 RemoveResource(this.boldFont);
3194 this.boldFont = boldFont;
3198 SetInitSize(initSize);
3201 bool OnMouseMove(int x, int y, Modifiers mods)
3203 bool isTimer = false;
3204 int realX = x, realY = y;
3206 if(insideNotifySelect) return true;
3208 if(style.alwaysEdit && style.resizable &&
3209 resizingField && !(mods.isSideEffect))
3212 DataField field = resizingField;
3213 field.width = startWidth + x - resizeX;
3214 field.width = Max(field.width, - EXTRA_SPACE);
3216 AdaptToFieldWidth(field, true);
3220 if(style.alwaysEdit && style.resizable)
3222 int vx = -scroll.x - 1;
3225 if(style.collapse && !(style.treeBranch))
3228 for(field = fields.first; field; field = field.next)
3230 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3231 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3237 cursor = guiApp.GetCursor(sizeWE);
3241 vx += width + EXTRA_SPACE;
3245 if((editData && editData.visible) || (style.alwaysEdit))
3248 if(x == MAXINT && y == MAXINT)
3255 // ADDED THIS CHECK FOR FieldDropBox LEAKS
3256 if(/*!mods.isSideEffect && */(rolledOver || !dragging))
3258 int rowY = (style.header) ? rowHeight : 0;
3259 DataRow row = null, nextRow;
3266 ((vertScroll && vertScroll.visible &&
3267 (y < 0 || y >= clientSize.h)) ||
3268 (horzScroll && horzScroll.visible &&
3269 (x < 0 || x >= clientSize.w))))
3274 if(vertScroll && vertScroll.visible &&
3275 (y < 0 || y >= clientSize.h))
3276 vertScroll.Action((y<0)?up:down, 0, 0);
3277 if(horzScroll && horzScroll.visible &&
3278 (x < 0 || x >= clientSize.w))
3279 horzScroll.Action((x<0)?up:down, 0, 0);
3285 // This must be done after the scrolling took place
3286 rowIndex = firstRowShown ? firstRowShown.index : -1;
3288 y = Min(y, clientSize.h - ((dragRow && style.moveRows) ? rowHeight : 0)-1);
3289 for(row = firstRowShown; row; row = nextRow, rowIndex ++)
3291 nextRow = row.GetNextRow();
3293 if(rowY > y || !nextRow)
3299 if(dragRow && style.moveRows)
3301 if(row && row == currentRow)
3302 row = row.GetNextRow();
3304 if(row && row.parent == currentRow)
3305 row = row.GetNextRow();
3308 if(row && currentRow != row)
3310 if(dragRow && style.moveRows)
3312 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
3314 else if(style.multiSelect)
3317 for(thisRow = rows.first; thisRow; thisRow = thisRow.GetNextRow())
3318 if((thisRow.selectedFlag == selected || thisRow.selectedFlag == tempSelected) ||
3324 if(dropIndex != rowIndex)
3326 dropIndex = rowIndex;
3332 else if((style.freeSelect || dragging) && ((realX>= 0 && realY >= 0 && realX< clientSize.w && realY < clientSize.h) || rolledOver))
3334 if(!(style.multiSelect))
3336 if(currentRow)currentRow.selectedFlag = unselected;
3337 if(row)row.selectedFlag = selected;
3341 if(style.multiSelect)
3345 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3347 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3348 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3351 if(rowIndex >= clickedRow.index)
3353 for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
3355 selRow.selectedFlag = (selRow.selectedFlag == selected) ? tempUnselected : tempSelected;
3362 for(selRow = row; selRow; selRow = selRow.GetNextRow())
3364 selRow.selectedFlag = (selRow.selectedFlag == selected) ? tempUnselected : tempSelected;
3365 if(selRow == clickedRow)
3371 if(style.freeSelect)
3372 NotifyHighlight(master, this, currentRow, mods);
3375 insideNotifySelect = true;
3376 NotifySelect(master, this, currentRow, mods);
3377 insideNotifySelect = false;
3380 if(style.alwaysEdit && currentRow)
3381 currentRow.Edit(currentField);
3388 bool OnMouseOver(int x, int y, Modifiers mods)
3395 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
3397 // TOCHECK: WAS THIS MISSING ? CHECK FOR SLOWDOWN
3398 if(!active) Update(null);
3400 if(!active && (!swap || !swap.isModal))
3402 // true: destroy edit box
3403 HideEditBox(true, true, false);
3405 else if(!swap || !swap.isModal)
3407 // Bring back edit box
3408 if(currentRow && style.alwaysEdit)
3410 currentRow.Edit(currentField ? currentField : null);
3414 return true; //NotifyActivate(master, this, active, swap, 0);
3418 bool OnButtonDown(int x, int y, Modifiers mods, bool right)
3421 // Check to see if we're dragging the vertical divider
3422 if(style.alwaysEdit && style.resizable && !right)
3424 int vx = -scroll.x - 1;// + EXTRA_SPACE;// / 2 - 1;
3427 if(style.collapse && !(style.treeBranch))
3430 for(field = fields.first; field; field = field.next)
3432 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3433 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3439 resizingField = field.prev;
3441 startWidth = resizingField.width;
3443 SetMouseRangeToClient();
3447 vx += width + EXTRA_SPACE;
3451 if(!(style.freeSelect))
3453 int rowY = (style.header) ? rowHeight : 0;
3455 int rowIndex = firstRowShown ? firstRowShown.index : -1;
3456 DataRow previousRow = currentRow;
3457 DataRow newCurrentRow = null;
3458 bool moveMultiple = false;
3459 int numSelected = 0;
3460 int rowStart = -scroll.x;
3462 if(style.multiSelect)
3469 for(row = rows.first; row; row = row.GetNextRow())
3471 if(row.selectedFlag == tempSelected)
3472 row.selectedFlag = selected;
3473 else if(row.selectedFlag == tempUnselected)
3474 row.selectedFlag = unselected;
3475 if(row.selectedFlag == selected)
3482 for(row = firstRowShown; row; row = row.GetNextRow(), rowIndex ++)
3485 if(rowY > y || (style.multiSelect && !row.GetNextRow()))
3488 if(style.treeBranch)
3491 for(parent = (style.rootCollapse) ? row.parent : (row.parent ? row.parent.parent : null); parent; parent = parent.parent)
3497 /* THIS WAS TOO STRICT:
3498 if(style.collapse && row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)) &&
3499 (x >= rowStart + 3 + plusIndent && y >= rowY - rowHeight + PLUSY && x <= rowStart + 11 + plusIndent && y <= rowY - rowHeight + PLUSY + 8))
3501 if(style.collapse &&
3502 (x >= rowStart && y >= rowY - rowHeight && x <= rowStart + 18 + plusIndent && y <= rowY + rowHeight-1))
3504 if(row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)) && x >= plusIndent)
3505 row.collapsed = !row.collapsed;
3512 newCurrentRow = row;
3514 if(style.multiSelect)
3516 // Deselect everything if user didn't clicked on a row
3520 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3521 selRow.selectedFlag = unselected;
3523 //clickedRowIndex = rowIndex;
3525 else if(style.moveRows && !(mods.shift) &&
3526 (row.selectedFlag == selected || row.selectedFlag == tempSelected) &&
3527 !right && !(mods.isActivate))
3528 moveMultiple = true;
3534 if(row.selectedFlag == tempUnselected || row.selectedFlag == unselected)
3536 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3537 selRow.selectedFlag = unselected;
3538 row.selectedFlag = selected;
3541 //clickedRowIndex = rowIndex;
3547 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3548 selRow.selectedFlag = unselected;
3552 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3554 if(selRow != clickedRow)
3556 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3557 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3564 if(rowIndex >= clickedRow.index)
3566 for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
3570 if(selRow != clickedRow)
3572 if(selRow.selectedFlag)
3573 selRow.selectedFlag = tempUnselected;
3575 selRow.selectedFlag = tempSelected;
3579 selRow.selectedFlag = selected;
3586 for(selRow = row; selRow; selRow = selRow.GetNextRow())
3590 if(selRow != clickedRow)
3592 if(selRow.selectedFlag)
3593 selRow.selectedFlag = tempUnselected;
3595 selRow.selectedFlag = tempSelected;
3599 selRow.selectedFlag = selected;
3600 if(selRow == clickedRow)
3609 if(row.selectedFlag)
3610 row.selectedFlag = tempUnselected;
3611 else row.selectedFlag = tempSelected;
3614 row.selectedFlag = tempSelected;
3616 //clickedRowIndex = rowIndex;
3626 // true: destroy edit box
3629 incref newCurrentRow;
3632 if(currentRow != newCurrentRow)
3633 HideEditBox(true, true, false);
3637 if(newCurrentRow._refCount <= 1)
3638 delete newCurrentRow;
3640 newCurrentRow._refCount--;
3645 if(!(style.multiSelect))
3647 if(currentRow) currentRow.selectedFlag = unselected;
3648 if(newCurrentRow) newCurrentRow.selectedFlag = selected;
3652 if(currentRow != newCurrentRow)
3655 // true: destroy edit box
3658 //incref newCurrentRow;
3659 incref newCurrentRow;
3662 HideEditBox(true, true, false);
3667 int headerSize = ((style.header) ? rowHeight : 0);
3668 int height = clientSize.h + 1 - headerSize;
3670 /*if(newCurrentRow._refCount <= 1)
3671 delete newCurrentRow;
3674 newCurrentRow._refCount--;
3675 //newCurrentRow._refCount--;
3678 currentRow = newCurrentRow;
3680 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
3681 SetScrollPosition(scroll.x,
3682 currentRow.index * rowHeight - height + rowHeight);
3683 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
3685 int line = currentRow ? currentRow.index * rowHeight : 0;
3686 //SNAPUP(line, rowHeight);
3687 SetScrollPosition(scroll.x, line);
3690 // GO THROUGH SetCurrentRow eventually?
3691 // SetCurrentRow(newCurrentRow, true);
3695 if(style.freeSelect)
3696 NotifyHighlight(master, this, currentRow, mods);
3697 else if((moveMultiple || (!(style.multiSelect) && previousRow == currentRow)) &&
3698 newCurrentRow && !(mods.shift))
3702 if(!(mods.isActivate))
3706 dragRow = currentRow;
3712 if(editData && editData.visible && style.alwaysEdit)
3719 if(style.collapse && !style.treeBranch)
3722 for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3724 indent += (style.treeBranch) ? 20 : 15;
3727 for(field = fields.first; field; field = field.next)
3729 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3730 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3732 if(!field.prev) width -= indent;
3733 if(x >= sx && x < sx + width)
3737 if(field == currentField)
3738 editData.Deactivate();
3741 currentRow.Edit(field);
3742 editData.Activate();
3745 else if(!(mods.ctrl) && numSelected <= 1)
3746 editRow = currentRow;
3748 if(style.noDragging && newCurrentRow)
3749 NotifyReclick(master, this, newCurrentRow, mods);
3753 // If the user clicked exactly on the edited field,
3755 if(editData && editData.visible && newCurrentRow)
3761 if(style.collapse && !(style.treeBranch))
3766 for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3768 indent += (style.treeBranch) ? 20 : 15;
3772 for(field = fields.first; field; field = field.next)
3774 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3775 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3776 if(!field.prev) width -= indent;
3777 if(x >= sx && x < sx + width && newCurrentRow)
3782 if(field) //x >= sx && x < sx + width && newCurrentRow)
3784 if(field == currentField)
3785 editData.Activate();
3787 newCurrentRow.Edit(currentField);*/
3789 else if(style.noDragging && newCurrentRow)
3790 NotifyReclick(master, this, newCurrentRow, mods);
3792 else if(style.noDragging && newCurrentRow)
3793 NotifyReclick(master, this, newCurrentRow, mods);
3800 if(result && style.alwaysEdit && currentRow)
3804 DataField field = null;
3809 if(style.collapse && !style.treeBranch)
3812 for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3814 indent += (style.treeBranch) ? 20 : 15;
3817 for(field = fields.first; field; field = field.next)
3819 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3820 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3822 if(!field.prev) width -= indent;
3823 if(x >= sx && x < sx + width)
3825 f = currentField = field;
3832 // Moved NotifySelect after setting currentField for the NotifySelect implementation to be aware of which field is now selected (e.g. WatchesView)
3833 result = NotifySelect(master, this, currentRow, mods);
3834 if(result && style.alwaysEdit && currentRow)
3836 // In case the user specifically clicked on a field (f is set), override any change to currentField that NotifySelect could have done
3837 currentRow.Edit(f ? f : currentField);
3839 // If the user clicked exactly on the edited field,
3841 if(editData && editData.visible && newCurrentRow)
3845 editData.Activate();
3847 else if(style.noDragging && newCurrentRow)
3848 NotifyReclick(master, this, newCurrentRow, mods);
3851 else if(style.noDragging && newCurrentRow)
3852 NotifyReclick(master, this, newCurrentRow, mods);
3856 For drop box to capture...
3859 if(x < 0 || y < 0 || x >= clientSize.w || y >= clientSize.h)
3862 master.parent.Activate();
3871 if(!style.noDragging)
3876 if(x >= 0 && y >= 0 && x < clientSize.w && y < clientSize.h)
3883 OnLeftButtonUp(x, y, mods);
3888 bool OnLeftButtonDown(int x, int y, Modifiers mods)
3890 return OnButtonDown(x,y, mods, false);
3893 bool OnLeftButtonUp(int x, int y, Modifiers mods)
3895 if(resizingField && style.alwaysEdit)
3897 Window::FreeMouseRange();
3899 resizingField = null;
3902 if(dragRow || editRow)
3904 DataRow row, switchRow = rows.last;
3905 int rowY = (style.header) ? rowHeight : 0;
3906 while(switchRow.lastRow) switchRow = switchRow.lastRow;
3907 for(row = firstRowShown; row; row = row.GetNextRow())
3916 if(editRow == switchRow && y >= 0)
3921 for(field = fields.first; field; field = field.next)
3923 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3924 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3927 if(fieldX > x + scroll.x)
3931 if(field && field.editable)
3933 // true: destroy edit box
3934 HideEditBox(true, true, false);
3935 PopupEditBox(field, false);
3937 else if(!style.noDragging)
3938 NotifyReclick(master, this, currentRow, mods);
3940 else if(style.moveRows && switchRow)
3942 if(dragRow == switchRow && movedRow == false)
3944 DataRow row = dragRow;
3948 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3949 selRow.selectedFlag = unselected;
3953 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3955 if(selRow != clickedRow)
3957 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3958 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3964 if(row.selectedFlag)
3965 row.selectedFlag = tempUnselected;
3966 else row.selectedFlag = tempSelected;
3969 row.selectedFlag = tempSelected;
3974 if(style.multiSelect)
3976 if(!switchRow.selectedFlag)
3978 bool foundSwitch = false;
3981 DataRow afterRow = switchRow.prev;
3982 for(row = rows.first; row; row = next)
3984 next = row.GetNextRow();
3985 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
3987 if(!foundSwitch && !after)
3990 afterRow = switchRow;
3992 if(!after || !(row.selectedFlag == selected || row.selectedFlag == tempSelected) ||
3999 else if(row == switchRow)
4006 for(row = rows.first; row; row = row.GetNextRow())
4008 if(row == switchRow || row == dragRow)
4012 // Switch row first: move before
4013 if(row == switchRow)
4015 DataRow actualMoveRow;
4017 if(!switchRow.prev && switchRow.parent == dragRow.parent)
4018 actualMoveRow = null;
4021 actualMoveRow = switchRow.prev ? switchRow.prev : switchRow;
4022 while(actualMoveRow && actualMoveRow.parent != dragRow.parent && actualMoveRow.parent)
4023 actualMoveRow = actualMoveRow.parent;
4026 if(!actualMoveRow || (actualMoveRow && actualMoveRow.parent == dragRow.parent))
4027 if(NotifyMove(master, this, actualMoveRow, mods))
4029 dragRow.Move(actualMoveRow);
4030 NotifyMoved(master, this, actualMoveRow, mods);
4033 // Dragged row first: move after
4036 DataRow actualMoveRow = switchRow;
4037 DataRow nextRow = switchRow.GetNextRow();
4039 while(nextRow && nextRow.parent != dragRow.parent)
4040 nextRow = nextRow.parent ? nextRow.parent.next : null;
4042 actualMoveRow = nextRow.prev;
4045 actualMoveRow = dragRow.parent ? dragRow.parent.subRows.last : rows.last;
4047 if(!actualMoveRow || (actualMoveRow != dragRow && actualMoveRow.parent == dragRow.parent))
4048 if(NotifyMove(master, this, actualMoveRow, mods))
4050 dragRow.Move(actualMoveRow);
4051 NotifyMoved(master, this, actualMoveRow, mods);
4067 if(dragging || style.freeSelect)
4071 rolledOver = dragging = false;
4073 if(x >= 0 && y >= 0 && x < clientSize.w && y < clientSize.h && currentRow && style.freeSelect)
4077 result = NotifySelect(master, this, currentRow, mods);
4078 if(style.alwaysEdit)
4079 currentRow.Edit(currentField);
4083 // if(!(style.freeSelect))
4089 bool OnLeftDoubleClick(int x, int y, Modifiers mods)
4091 int rowStart = -scroll.x;
4093 int rowY = (style.header) ? rowHeight : 0;
4096 OnLeftButtonUp(x,y,mods);
4097 if(style.alwaysEdit)
4099 if(!(style.collapse) || x > 15)
4100 if(editData && editData.visible)
4102 editData.Activate();
4103 NotifyDoubleClick(master, this, x, y, mods);
4107 for(row = firstRowShown; row; row = row.GetNextRow())
4110 if(rowY > y || (style.multiSelect && !row.GetNextRow()))
4112 if(style.treeBranch)
4115 for(parent = (style.rootCollapse) ? row.parent : (row.parent ? row.parent.parent : null); parent; parent = parent.parent)
4124 if((row && style.collapse && (x >= rowStart && x <= rowStart + 18 + plusIndent)) ||
4125 NotifyDoubleClick(master, this, x, y, mods))
4129 if(row && row.subRows.first)
4131 row.collapsed = !row.collapsed;
4135 // We need to return true here so that OnLeftButtonDown can popup the DataBox Editors
4141 bool OnRightButtonDown(int x, int y, Modifiers mods)
4143 return OnButtonDown(x,y, mods, true);
4146 bool OnRightButtonUp(int x, int y, Modifiers mods)
4148 OnLeftButtonUp(x,y,mods);
4149 return NotifyRightClick(master, this, x, y, mods);
4152 bool GoToLetter(unichar ch, bool keyHit)
4154 bool result = false;
4156 bool checkNextField = true;
4157 int len = keyHit ? 0 : strlen(typedString);
4159 typedString = renew typedString char[len + 2];
4160 typedString[len++] = (char)tolower(ch); // TODO: FIX UNICODE
4161 typedString[len] = '\0';
4163 for(field = fields.first; field; field = field.next)
4165 DataRow startRow = currentRow ? currentRow : rows.first;
4167 if(startRow && field.dataType && field.dataType._vTbl[__ecereVMethodID_class_OnGetString] && ch)
4170 bool looped = false;
4171 if(len == 1 && currentRow)
4172 startRow = (next = startRow.GetNextRow(), (next ? next : rows.first));
4174 for(row = startRow; row != startRow || !looped; next = row.GetNextRow(), row = next ? next : rows.first)
4176 void * data = row.GetData(field);
4177 char tempString[1024] = "";
4178 bool needClass = false;
4179 const char * string = data ? ((const char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, data, tempString, null, &needClass) : null;
4181 if(string && string[0])
4182 checkNextField = false;
4183 if(string && string[0] && !strnicmp(string, typedString, len))
4185 if(style.multiSelect)
4190 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4191 selRow.selectedFlag = unselected;
4192 row.selectedFlag = selected;
4194 SetCurrentRow(row, true);
4201 if(typingTimeOut && !keyHit)
4202 typingTimer.Start();
4203 if(!result || !typingTimeOut || keyHit)
4204 typedString[len-1] = '\0';
4206 if(!checkNextField || result) break;
4211 bool OnKeyDown(Key key, unichar ch)
4215 if(key == enter || key == keyPadEnter)
4217 if(editData && editData.visible && editData.active)
4219 HideEditBox(true, false, false);
4223 else if(key == escape)
4225 if(resizingField || movingFields || (editData && editData.visible) || dragRow)
4227 if(editData && editData.visible && style.alwaysEdit && !editData.active)
4229 // false: dont destroy edit box
4230 HideEditBox(false, false, false);
4233 resizingField.width = startWidth;
4234 AdaptToFieldWidth(resizingField, true);
4235 resizingField = null;
4248 movingFields = false;
4249 draggingField = null;
4255 if(!currentField || !currentField.editable)
4256 for(field = fields.first; field; field = field.next)
4260 currentField = field;
4264 if((key == f2 || (style.alwaysEdit && (key == ctrlV || key == ctrlC || key == ctrlX || key == shiftInsert || key == ctrlInsert || key == shiftDel))) &&
4265 currentField && currentField.editable)
4267 PopupEditBox(currentField, false);
4268 if(editData && editData.visible)
4270 if(style.alwaysEdit)
4272 editData.Activate();
4273 if(key == ctrlV || key == ctrlC || key == ctrlX || key == shiftInsert || key == ctrlInsert || key == shiftDel)
4275 editData.OnKeyHit(key, ch);
4279 // For Installer to pop up file dialog
4280 NotifyKeyDown(master, this, currentRow, key, ch);
4286 if(!NotifyKeyDown(master, this, currentRow, key, ch))
4289 // Editable fields...
4292 if(style.alwaysEdit && editData && editData.visible)
4293 return editData.OnKeyDown(key, ch);
4294 return true; // We want to pick up the OnKeyHit to replace contents, but skip GoToLetter
4297 if(ch >=32 && ch != 128 && !key.alt && !key.ctrl && GoToLetter(ch, false))
4299 /*if(inactive && window.state != Hidden)
4300 NotifyHighlight(master, this, currentRow, 0);
4303 NotifySelect(master, this, currentRow, 0);
4310 bool OnKeyHit(Key key, unichar ch)
4312 if(!ch && !key.alt && !key.ctrl)
4314 key.code = (SmartKey)key.code;
4316 if(ch >= 32 && !key.alt && !key.ctrl && ch != 128)
4319 if(!currentField || !currentField.editable)
4320 for(field = fields.first; field; field = field.next)
4324 currentField = field;
4328 if(currentField && currentField.editable)
4330 if((!editData || !editData.visible) || !editData.active)
4332 PopupEditBox(currentField, false);
4333 if(editData && editData.visible)
4335 editData.Activate();
4336 editData.OnKeyHit(key, ch);
4343 if(editData && editData.visible && ch && !key.alt && !key.ctrl && editData.active && (key.code != tab || (editData._class == class(EditBox) && ((EditBox)editData).tabKey)))
4346 if(!key.alt && (style.multiSelect || !key.ctrl))
4351 if(style.alwaysEdit)
4356 for(field = currentField.prev; field; field = field.prev)
4360 currentField = field;
4361 HideEditBox(true, true, false);
4362 PopupEditBox(currentField, false);
4368 if(style.collapse && currentRow /*&& !currentField*/) // THIS PREVENTED COLLAPSING THE PROPERTY SHEET
4370 if(currentRow.subRows.first && !currentRow.collapsed)
4372 currentRow.collapsed = true;
4374 else if(currentRow.parent)
4375 SetCurrentRow(currentRow.parent, true);
4380 if(style.collapse && currentRow && currentRow.subRows.first)
4382 if(currentRow.collapsed)
4383 currentRow.collapsed = false;
4385 SetCurrentRow(currentRow.subRows.first, true);
4388 else if(style.alwaysEdit)
4393 for(field = currentField.next; field; field = field.next)
4397 currentField = field;
4398 HideEditBox(true, true, false);
4399 PopupEditBox(currentField, false);
4407 case pageDown: case pageUp:
4408 case end: case home:
4410 int headerSize = ((style.header) ? rowHeight : 0);
4411 int height = clientSize.h + 1 - headerSize;
4414 // true: destroy edit box
4415 // !!! TESTING true HERE !!!
4416 HideEditBox(true, true, false);
4417 // HideEditBox(false, true, false);
4419 oldRow = currentRow;
4421 SNAPDOWN(height, rowHeight);
4422 if((!currentRow || key.code == home) && key.code != end)
4424 currentRow = rows.first;
4432 if(!(style.multiSelect) && currentRow && !currentRow.selectedFlag)
4435 next = currentRow.GetNextRow();
4442 if(!(style.multiSelect) && currentRow && !currentRow.selectedFlag)
4445 next = currentRow.GetPrevRow();
4453 currentRow = lastRow.GetLastRow();
4459 currentRow && (next = currentRow.GetPrevRow()) && c < height / rowHeight;
4460 c++, currentRow = next);
4467 currentRow && (next = currentRow.GetNextRow()) && c < height / rowHeight;
4468 c++, currentRow = next);
4473 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
4474 SetScrollPosition(scroll.x, currentRow.index * rowHeight - height + rowHeight);
4475 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
4476 SetScrollPosition(scroll.x, currentRow ? currentRow.index * rowHeight : 0);
4478 if(style.multiSelect)
4482 if(!(key.shift) && (key.ctrl))
4485 for(row = rows.first; row; row = row.GetNextRow())
4487 if(row.selectedFlag == tempSelected)
4488 row.selectedFlag = selected;
4489 else if(row.selectedFlag == tempUnselected)
4490 row.selectedFlag = unselected;
4496 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4497 selRow.selectedFlag = unselected;
4501 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4503 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
4504 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
4510 if(currentRow.index >= clickedRow.index)
4512 for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
4516 if(selRow.selectedFlag) selRow.selectedFlag = tempUnselected; else selRow.selectedFlag = tempSelected;
4519 selRow.selectedFlag = selected;
4520 if(selRow == currentRow)
4526 for(selRow = currentRow; selRow; selRow = selRow.GetNextRow())
4530 if(selRow.selectedFlag) selRow.selectedFlag = tempUnselected; else selRow.selectedFlag = tempSelected;
4533 selRow.selectedFlag = selected;
4534 if(selRow == clickedRow)
4541 if(!(key.ctrl) && currentRow)
4543 currentRow.selectedFlag = selected;
4546 clickedRow = currentRow;
4551 if(oldRow) oldRow.selectedFlag = unselected;
4552 if(currentRow) currentRow.selectedFlag = selected;
4557 if(style.freeSelect)
4558 NotifyHighlight(master, this, currentRow, 0);
4560 NotifySelect(master, this, currentRow, 0);
4562 if(style.alwaysEdit && currentRow)
4563 currentRow.Edit(currentField /*null*/);
4570 if(style.multiSelect && currentRow)
4572 if(currentRow.selectedFlag)
4575 currentRow.selectedFlag = unselected;
4578 currentRow.selectedFlag = selected;
4581 if(style.freeSelect)
4582 NotifyHighlight(master, this, currentRow, 0);
4584 NotifySelect(master, this, currentRow, 0);
4591 if(!NotifyKeyHit(master, this, currentRow, key, ch))
4594 if(ch >=32 && ch != 128 && !key.alt && !key.ctrl && GoToLetter(ch, true))
4596 /*if(inactive && window.state != Hidden)
4597 return NotifyHighlight(master, this, currentRow, 0);
4600 return NotifySelect(master, this, currentRow, 0);
4607 void OnHScroll(ScrollBarAction action, int position, Key key)
4612 void OnVScroll(ScrollBarAction action, int position, Key key)
4617 for(firstRowShown = rows.first; firstRowShown; firstRowShown = next)
4619 next = firstRowShown.GetNextRow();
4620 if(y >= position || !next) break;
4630 DataRow firstRowShown;
4634 DataField sortField;
4638 public double typingTimeOut;
4651 if(guiApp.GetKeyState(shift)) mods.shift = true;
4652 if(guiApp.GetKeyState(alt)) mods.alt = true;
4653 if(guiApp.GetKeyState(control)) mods.ctrl = true;
4654 OnMouseMove(MAXINT, MAXINT, mods);
4662 delay = 0.5; // typingTimeOut
4667 typedString[0] = '\0';
4669 // The next line was commented... Why? When commented typing words stops working ( only first character jumps )
4675 bool dragging, rolledOver;
4684 // For editing fields
4686 DataField currentField;
4689 // For moving fields
4690 DataField draggingField, dropField;
4693 // For resizing fields
4694 DataField resizingField;
4695 int resizeX, oldX, startWidth;
4698 FontResource boldFont;
4701 // Only used for OnMouseMove so far, for avoiding problems with consequential mouse moves
4702 bool insideNotifySelect;
4703 ColorAlpha selectionColor, selectionText, stippleColor;
4704 stippleColor = 0xFFFFFF80;