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
58 property Class dataType
60 set { dataType = value; if(value) { alignment = (Alignment)value.defaultAlignment; } } // NOTE: Class::defaultAlignment does not seem to be used anywhere
61 get { return dataType; }
63 property bool editable { set { editable = value; } };
64 property bool fixed { set { fixed = value; } get { return fixed; } };
65 property Alignment alignment
70 if(headButton) headButton.alignment = value;
71 if(listBox) listBox.Update(null);
73 get { return alignment; }
79 width = Max(value, -EXTRA_SPACE);
81 listBox.AdaptToFieldWidth(this, false);
85 property int index { get { return this ? index : 0; } };
94 for(field = listBox.fields.first; field; field = field.next)
96 if(index == value - 2)
109 for(field = listBox.fields.first; field; field = field.next)
121 property int sortOrder { get { return this ? sortOrder : 0; } };
122 property const char * header
128 headButton.text = header;
131 property void * userData
139 return this ? userData : null;
142 property bool freeData
144 set { freeData = value; } get { return freeData; }
146 property DataField prev { get { return prev; } };
147 property DataField next { get { return next; } };
149 void Move(DataField after)
153 listBox.fields.Move(this, after);
156 listBox.OnResize(listBox.clientSize.w, listBox.clientSize.h);
157 listBox.Update(null);
163 if(listBox && dataType)
165 Display display = listBox.display;
166 Font boldFont = listBox.boldFont.font;
167 Font font = listBox.fontObject;
171 display.FontExtent(boldFont, header, strlen(header), &width, null);
172 width += EXTRA_SPACE;
173 for(row = listBox.firstRow; row; row = row.GetNextRow())
177 for(i = 0, cell = row.cells.first; i != index; i++, cell = cell.next);
178 if(cell && cell.isSet && dataType)
180 static char tempString[4096];
183 if(dataType.type == normalClass || dataType.type == noHeadClass)
184 string = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, cell.data[0], tempString, userData, null);
186 string = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, cell.data, tempString, userData, null);
188 display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, null);
190 display.FontExtent(row.header ? boldFont : font, "", 0, &tw, null);
191 if(tw > width) width = tw;
195 property::width = width;
202 // property::dataType = "String";
203 property::dataType = "char *";
215 headButton.Destroy(0);
220 listBox.fields.Remove(this);
221 for(field = listBox.fields.first; field; field = field.next)
223 if(field.index >= index)
226 if(listBox.currentField == this)
227 listBox.currentField = null;
229 listBox.OnResize(listBox.clientSize.w, listBox.clientSize.h);
234 DataField prev, next;
258 property int64 tag { set { if(this) tag = value; } get { return this ? tag : 0; } };
259 property DataRow previous { get { return prev; } };
260 property DataRow next { get { return next; } };
261 property int index { get { return (this && (!parent || parent.IsExpanded())) ? index : -1; } };
262 property const char * string
264 set { SetData(listBox.fields.first, value); }
265 get { return GetData(listBox.fields.first); }
267 property bool isHeader { set { header = value; } get { return this ? header : false; } };
268 property BitmapResource icon { set { if(this) icon = value; } get { return this ? icon : null; } };
269 property bool collapsed
273 if(this && collapsed != value)
276 if(parent.IsExpanded())
283 for(search = subRows.first; search; search = search.next)
284 search.selectedFlag = 0;
286 if(listBox.clickedRow && !listBox.clickedRow.parent.IsExpanded())
288 listBox.clickedRow = GetNextRow();
289 if(!listBox.clickedRow)
290 listBox.clickedRow = this;
292 if(listBox.currentRow && !listBox.currentRow.parent.IsExpanded())
294 listBox.SetCurrentRow(this, true);
296 if(listBox.firstRowShown && !listBox.firstRowShown.parent.IsExpanded())
298 listBox.firstRowShown = GetPrevRow();
299 if(!listBox.firstRowShown)
300 listBox.firstRowShown = this;
305 for(search = GetNextRow(); search; search = search.GetNextRow())
307 listBox.rowCount = ix;
309 listBox.HideEditBox(false, false, true);
311 listBox.SetScrollArea(
313 (listBox.rowCount * listBox.rowHeight) +
314 ((listBox.style.header) ? listBox.rowHeight : 0) -
315 ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
316 listBox.Update(null);
317 listBox.NotifyCollapse(listBox.master, listBox, this, value);
321 if(this && !skipCheck)
322 listBox.CheckConsistency();
325 get { return this ? collapsed : false; }
327 property bool selected
333 selectedFlag = value ? selected : unselected;
334 listBox.Update(null);
337 get { return selectedFlag == selected || selectedFlag == tempSelected; }
339 property DataRow parent
343 if(this && (value != this))
346 DataRow after = value ? value.subRows.last : listBox.rows.last;
347 int ixCount = (!collapsed && subRows.count) ? GetLastRow().index - index + 1 : 1;
348 if(parent.IsExpanded())
350 for(search = GetNextRow(); search; search = search.GetNextRow())
351 search.index -= ixCount;
352 listBox.rowCount -= ixCount;
355 listBox.HideEditBox(false, false, true);
358 if(this == listBox.clickedRow)
360 listBox.clickedRow = GetNextRow();
361 if(!listBox.clickedRow)
362 listBox.clickedRow = GetPrevRow();
365 if(this == listBox.currentRow)
367 DataRow newCurrentRow = GetNextRow();
368 if(!listBox.newCurrentRow)
369 listBox.newCurrentRow = GetPrevRow();
370 listBox.SetCurrentRow(newCurrentRow, true);
373 if(this == listBox.firstRowShown)
375 listBox.firstRowShown = GetPrevRow();
376 if(!listBox.firstRowShown)
377 listBox.firstRowShown = GetNextRow();
381 (parent ? parent.subRows : listBox.rows).Remove(this);
384 value.subRows.Insert(after, this);
386 listBox.rows.Insert(after, this);
390 if(value && listBox.style.expandOnAdd)
393 value.skipCheck = true;
395 value.collapsed = false;
397 value.skipCheck = false;
401 if(value.IsExpanded())
405 if(after && after.subRows.first && !after.collapsed)
407 search = after.GetLastRow();
408 index = search.index + 1;
411 index = after ? (after.index + 1) : (index + 1);
413 listBox.rowCount += ixCount;
417 for(search = GetNextRow(); search; search = search.GetNextRow())
421 listBox.SetScrollArea(
423 (listBox.rowCount * listBox.rowHeight) +
424 ((listBox.style.header) ? listBox.rowHeight : 0) -
425 ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
426 if(listBox.style.autoScroll)
427 listBox.SetScrollPosition(0, MAXINT - listBox.rowHeight);
429 // TESTING THIS HERE...
431 listBox.Sort(listBox.sortField, listBox.sortField.sortOrder);
434 int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
435 int height = listBox.clientSize.h + 1 - headerSize;
436 if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
437 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
438 else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
440 int line = listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0;
441 listBox.SetScrollPosition(listBox.scroll.x, line);
444 listBox.OnVScroll(0, listBox.scroll.y, 0);
446 listBox.Update(null);
454 property DataRow lastRow { get { return this ? subRows.last : null; } };
455 property DataRow firstRow { get { return this ? subRows.first : null; } };
457 void Edit(DataField field)
463 if(!field || !field.editable)
465 for(field = listBox.fields.first; field; field = field.next)
466 if(field.editable) break;
468 if(field && field.editable)
470 listBox.SetCurrentRow(this, true);
471 listBox.PopupEditBox(field, false);
477 // NOTE: This does not support reparenting (Use row.parent = first)
478 void Move(DataRow after)
483 if(listBox && prev != after)
486 int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
487 int height = listBox.clientSize.h + 1 - headerSize;
488 int ixCount = (!collapsed && subRows.count) ? GetLastRow().index - index + 1 : 1;
490 if(!after || after.index < index)
492 if((after && after == listBox.firstRowShown.prev) || (!after && !parent /*&& listBox.firstRowShown.prev*/))
493 listBox.firstRowShown = this;
495 // All rows between AFTER (exclusive) and ROW (exclusive) are incremented by one
496 // ROW is equal to AFTER's index + 1
498 for(search = after ? after.next : (parent ? parent.subRows.first : listBox.rows.first); search && search != this; search = search.GetNextRow())
499 search.index += ixCount;
501 if(after && after.subRows.first && !after.collapsed)
503 search = after.GetLastRow();
504 index = search.index + 1;
507 index = after ? (after.index + 1) : parent ? parent.index + 1 : 0;
509 // Fix indices of sub rows
513 for(c = 1, search = GetNextRow(); search && c < ixCount; c++, search = search.GetNextRow())
520 int afterIXCount = 1;
522 nextRow = GetNextRow();
523 if(this == listBox.firstRowShown)
524 listBox.firstRowShown = nextRow;
526 // All rows between ROW (exclusive) and AFTER (inclusive) are decremented by one
527 // ROW is equal to AFTER's index
529 for(search = nextRow; search; search = search.GetNextRow())
531 search.index -= ixCount;
532 if(search == after) break;
535 // Fix up's after's sub rows
536 if(after && !after.collapsed)
538 DataRow last = after.GetLastRow();
541 int ix = after.index+1;
542 for(search = after.GetNextRow(); search; search = search.GetNextRow())
546 if(search == last) break;
550 index = after.index + afterIXCount;
552 // Fix indices of sub rows
556 for(c = 1, search = GetNextRow(); search && c < ixCount; c++, search = search.GetNextRow())
560 (parent ? parent.subRows : listBox.rows).Move(this, after);
563 listBox.CheckConsistency();
566 listBox.HideEditBox(true, false, true);
569 if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
570 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
571 else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
573 int line = listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0;
574 //SNAPUP(line, listBox.rowHeight);
575 listBox.SetScrollPosition(listBox.scroll.x, line);
578 listBox.OnVScroll(0, listBox.scroll.y, 0);
580 listBox.modifiedDocument = true;
582 listBox.Update(null);
589 any_object GetData(DataField field)
593 ListBoxCell cell = listBox.GetCell(&this, &field);
594 if(cell && cell.isSet && cell.data)
596 if((field.dataType.type == normalClass || field.dataType.type == noHeadClass))
605 void * SetData(DataField field, any_object newData)
609 ListBoxCell cell = listBox.GetCell(&this, &field);
612 Class dataType = field.dataType;
616 if(dataType.type == normalClass || dataType.type == noHeadClass)
618 if(cell.data[0] && field.freeData)
619 ((void (*)(void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnFree])(dataType, cell.data[0]);
621 if(eClass_IsDerived(dataType, class(char *)) && field.freeData)
622 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCopy])(dataType, cell.data, newData);
624 cell.data[0] = (void *)newData;
628 // Free old data first
629 ((void (*)(void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnFree])(dataType, cell.data);
630 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCopy])(dataType, cell.data, newData);
634 listBox.modifiedDocument = true;
635 listBox.Update(null);
636 if(dataType && (dataType.type == normalClass || dataType.type == noHeadClass))
645 void UnsetData(DataField field)
649 ListBoxCell cell = listBox.GetCell(&this, &field);
652 Class dataType = field.dataType;
656 if(dataType.type == normalClass || dataType.type == noHeadClass)
658 if(cell.data[0] && field.freeData)
659 ((void (*)(void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnFree])(dataType, cell.data[0]);
664 // Free old data first
665 ((void (*)(void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnFree])(dataType, cell.data);
669 listBox.Update(null);
674 DataRow FindRow(int64 tag)
677 for(row = subRows.first; row; row = row.next)
679 if(!row.noneRow && row.tag == tag)
685 DataRow FindSubRow(int64 tag)
688 for(row = subRows.first; row; row = row.next)
690 if(!row.noneRow && row.tag == tag)
692 if(row.subRows.first)
694 DataRow subRow = row.FindSubRow(tag);
702 DataRow AddRowAfter(DataRow after)
712 subRows.Insert(after, row);
713 row.listBox = listBox;
717 for(c = 0; c<listBox.fields.count; c++)
719 for(field = listBox.fields.first; field; field = field.next)
720 if((int)field.index == c)
724 int size = (field.dataType && field.dataType.typeSize) ?
725 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
726 ListBoxCell cell = (ListBoxCell)new0 byte[size];
728 FillBytes(cell.data, 0, size - (uint)(uintptr)&((ListBoxCell)0).data);
737 if(after && after.subRows.first && !after.collapsed)
739 for(search = after.subRows.last; !search.collapsed && search.subRows.last; )
740 search = search.subRows.last;
741 row.index = search.index + 1;
744 row.index = after ? (after.index + 1) : (index + 1);
748 for(search = row.GetNextRow(); search; search = search.GetNextRow())
751 listBox.SetScrollArea(
753 (listBox.rowCount * listBox.rowHeight) +
754 ((listBox.style.header) ? listBox.rowHeight : 0) -
755 ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
756 if(listBox.style.autoScroll)
757 listBox.SetScrollPosition(0, MAXINT - listBox.rowHeight);
760 listBox.modifiedDocument = true;
763 listBox.CheckConsistency();
773 return AddRowAfter(subRows.last);
777 DataRow AddStringf(const char * format, ...)
782 char string[MAX_F_STRING];
784 va_start(args, format);
785 vsnprintf(string, sizeof(string), format, args);
786 string[sizeof(string)-1] = 0;
790 row.SetData(null, string);
796 DataRow AddString(const char * string)
802 row.SetData(listBox.fields.first, string);
812 subRows.offset = (uint)(uintptr)&((DataRow)0).prev;
817 ListBoxCell cell, next;
822 while((subRow = subRows.first))
824 subRows.Remove(subRow);
828 for(cell = cells.first; cell; cell = next, cellIndex++)
833 for(field = listBox.fields.first; field && field.index != cellIndex; field = field.next);
834 if(field && field.dataType)
836 // TOCHECK: Is this check good? Will need incref/decref sometime?
837 if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
839 if(cell.data[0] && field.freeData)
840 ((void (*)(void *, void *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnFree])(field.dataType, cell.data[0]);
843 ((void (*)(void *, void *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnFree])(field.dataType, cell.data);
853 return !this || (!collapsed && (!parent || parent.IsExpanded()));
856 int Compare(DataRow b, DataField sortField)
859 ListBoxCell cell1, cell2;
861 for(index = 0, cell1 = cells.first, cell2 = b.cells.first;
862 index != sortField.index;
863 index++, cell1 = cell1.next, cell2 = cell2.next);
865 if(!cell1.isSet && !cell2.isSet)
867 else if(!cell1.isSet)
869 else if(!cell2.isSet)
872 if(noneRow && !b.noneRow) return -1;
873 else if(!noneRow && b.noneRow) return 1;
874 else if(noneRow && b.noneRow) return 0;
876 if(sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare])
878 if(sortField.dataType.type == normalClass || sortField.dataType.type == noHeadClass)
880 result = ((int (*)(void *, void *, void *))(void *)sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare])(sortField.dataType,
881 (cell1.isSet && cell1.data) ? cell1.data[0] : null,
882 (cell2.isSet && cell2.data) ? cell2.data[0] : null);
886 result = ((int (*)(void *, void *, void *))(void *)sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare])(sortField.dataType,
887 cell1.isSet ? cell1.data : null,
888 cell2.isSet ? cell2.data : null);
891 return sortField.sortOrder * result;
894 void _SortSubRows(DataField field, int order)
897 for(search = subRows.first; search; search = search.next)
898 search._SortSubRows(field, order);
899 subRows.Sort(Compare, field);
902 public void SortSubRows(bool scrollToCurrent)
904 if(this && listBox && listBox.sortField)
906 _SortSubRows(listBox.sortField, listBox.sortField.sortOrder);
911 for(search = this; search; search = search.GetNextRow())
916 int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
917 int height = listBox.clientSize.h + 1 - headerSize;
918 if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
919 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
920 else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
921 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0);
922 listBox.OnVScroll(0, listBox.scroll.y, 0);
927 public DataRow GetPrevRow()
933 for(row = prev; row && !row.collapsed && row.subRows.last; row = row.subRows.last);
940 public DataRow GetNextRow()
944 if(subRows.first && !collapsed)
948 for(row = this; row; row = row.parent)
950 if(row.next) { row = row.next; break; }
956 private DataRow GetLastRow()
959 while(row && !row.collapsed && row.subRows.last)
960 row = row.subRows.last;
967 SelectedFlag selectedFlag;
978 public class ListBox : CommonControl
980 hasVertScroll = true;
981 // background = white;
983 snapVertScroll = true;
985 class_property(icon) = "<:ecere>controls/listBox.png";
989 property bool freeSelect { property_category $"Behavior" set { style.freeSelect = value; } get { return style.freeSelect; } };
990 property DataRow currentRow { property_category $"Private" /*"Behavior"*/ set { if(this) SetCurrentRow(value, false); } get { return this ? currentRow : null; } };
991 property DataField currentField
993 get { return currentField; }
994 // TODO: Document what this does
997 currentField = value;
998 HideEditBox(true, true, false);
999 if(value && value.editable)
1000 PopupEditBox(currentField, false);
1004 property int rowHeight
1006 property_category $"Appearance"
1007 isset { return style.heightSet; }
1012 style.heightSet = true;
1014 SetScrollLineStep(8, value);
1018 style.heightSet = false;
1023 get { return this ? rowHeight : 0; }
1025 property Seconds typingTimeout
1027 property_category $"Behavior"
1030 typedString[0] = '\0';
1031 typingTimer.delay = value;
1032 typingTimeOut = value;
1034 get { return typingTimeOut; }
1036 property bool moveRows { property_category $"Behavior" set { style.moveRows = value; } get { return style.moveRows; } };
1037 property bool moveFields { property_category $"Behavior" set { style.moveFields = value; } get { return style.moveFields; } };
1038 property bool resizable { property_category $"Behavior" set { style.resizable = value; } get { return style.resizable; } };
1039 property bool autoScroll { property_category $"Behavior" set { style.autoScroll = value; } get { return style.autoScroll; } };
1040 property bool alwaysHighLight { property_category $"Appearance" set { style.alwaysHL = value; } get { return style.alwaysHL; } };
1041 property bool hasClearHeader { property_category $"Appearance" set { style.clearHeader = value; if(value) property::hasHeader = true; } get { return style.clearHeader; } };
1042 property bool hasHeader
1044 property_category $"Appearance"
1047 if(value && !style.header)
1053 bevel = !guiApp.textMode && !style.clearHeader;
1054 dontScrollVert = true;
1057 NotifyPushed = HeaderPushed;
1058 NotifyClicked = HeaderClicked;
1059 NotifyDoubleClick = HeaderDoubleClicked;
1060 NotifyReleased = HeaderReleased;
1061 NotifyMouseMove = HeaderMouseMove;
1065 endBevel.visible = false;
1067 style.header = value;
1069 get { return style.header; }
1071 property bool multiSelect { property_category $"Behavior" set { style.multiSelect = value; } get { return style.multiSelect; } };
1072 property bool alwaysEdit { property_category $"Behavior" set { style.alwaysEdit = value; } get { return style.alwaysEdit; } };
1073 property bool fullRowSelect { property_category $"Appearance" set { style.fullRowSelect = value; } get { return style.fullRowSelect; } };
1074 property bool collapseControl { property_category $"Appearance" set { style.collapse = value; } get { return style.collapse; } };
1075 property bool treeBranches { property_category $"Appearance" set { style.treeBranch = value; } get { return style.treeBranch; } };
1076 property bool rootCollapseButton { property_category $"Appearance" set { style.rootCollapse = value; } get { return style.rootCollapse; } };
1077 property bool sortable { property_category $"Behavior" set { style.sortable = value; } get { return style.sortable; } };
1078 property bool noDragging { property_category $"Behavior" set { style.noDragging = value; } get { return style.noDragging; } };
1079 property bool fillLastField
1081 property_category $"Behavior"
1084 style.fillLastField = value;
1086 get { return style.fillLastField; }
1088 property int numSelections
1092 int numSelections = 0;
1093 if(this && style.multiSelect)
1096 for(row = rows.first; row; row = row.GetNextRow())
1097 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
1100 return numSelections;
1103 property int currentIndex
1105 get { return currentRow ? currentRow.index : -1; }
1107 property DataRow lastRow { get { return this ? rows.last : null; } };
1108 property DataRow firstRow { get { return this ? rows.first : null; } };
1109 property int rowCount { get { return rowCount; } };
1110 property DataField firstField { get { return this ? fields.first : null; } };
1111 property Color selectionColor { set { selectionColor = value; } get { return selectionColor; } isset { return selectionColor ? true : false; } };
1112 property Color selectionText { set { selectionText = value; } get { return selectionText; } isset { return selectionText ? true : false; } };
1113 property Color stippleColor { set { stippleColor = value; } get { return stippleColor; } };
1114 property bool expandOnAdd { set { style.expandOnAdd = value; } get { return style.expandOnAdd; } };
1117 virtual bool Window::NotifySelect(ListBox listBox, DataRow row, Modifiers mods);
1118 virtual bool Window::NotifyHighlight(ListBox listBox, DataRow row, Modifiers mods);
1119 virtual bool Window::NotifyReclick(ListBox listBox, DataRow row, Modifiers mods);
1120 virtual bool Window::NotifySort(ListBox listBox, DataField field, Modifiers mods);
1121 virtual bool Window::NotifyChanged(ListBox listBox, DataRow row);
1122 virtual bool Window::NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch);
1123 virtual bool Window::NotifyEdited(ListBox listBox, DataRow row);
1124 virtual bool Window::NotifyEditDone(ListBox listBox, DataRow row);
1125 virtual bool Window::NotifyMovedField(ListBox listBox, DataField field, Modifiers mods);
1126 virtual bool Window::NotifyMove(ListBox listBox, DataRow row, Modifiers mods);
1127 virtual bool Window::NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods);
1128 virtual bool Window::NotifyRightClick(ListBox listBox, int x, int y, Modifiers mods);
1129 virtual bool Window::NotifyResized(ListBox listBox, DataField field, Modifiers mods);
1130 virtual bool Window::NotifyCollapse(ListBox listBox, DataRow row, bool collapsed);
1131 virtual bool Window::NotifyKeyHit(ListBox listBox, DataRow row, Key key, unichar ch);
1132 virtual bool Window::NotifyModified(ListBox listBox, DataRow row);
1133 virtual bool Window::NotifyEditing(ListBox listBox, DataRow row);
1134 virtual void Window::NotifyMoved(ListBox listBox, DataRow row, Modifiers mods);
1137 private void CheckConsistency()
1142 for(r = rows.first; r; r = r.GetNextRow())
1144 if(r.index != index++)
1152 void AddField(DataField addedField)
1157 if(fields.first && ((DataField)fields.first).defaultField)
1159 DataField defaultField = fields.first;
1160 defaultField.Free();
1161 delete defaultField;
1165 addedField = DataField { };
1169 addedField.listBox = this;
1170 fields.Add(addedField);
1172 addedField.sortOrder = 1;
1173 addedField.index = numFields;
1177 addedField.headButton.Destroy(0);
1178 delete addedField.headButton;
1179 addedField.headButton = Button
1184 dontScrollVert = true;
1185 id = (int64)(intptr)addedField;
1186 text = addedField.header;
1187 bevel = (!guiApp.textMode && !style.clearHeader);
1189 alignment = addedField.alignment;
1190 NotifyPushed = HeaderPushed;
1191 NotifyClicked = HeaderClicked;
1192 NotifyDoubleClick = HeaderDoubleClicked;
1193 NotifyReleased = HeaderReleased;
1194 NotifyMouseMove = HeaderMouseMove;
1196 incref addedField.headButton;
1197 addedField.headButton.Create();
1200 addedField.headButton.background = Color { 0, 170, 0 };
1206 for(row = rows.first; row; )
1208 int size = (field.dataType && field.dataType.typeSize) ?
1209 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1210 ListBoxCell cell = (ListBoxCell)new0 byte[size];
1211 row.cells.Add(cell);
1212 FillBytes(cell.data, 0, size - (uint)(uintptr)&((ListBoxCell)0).data);
1215 if(row.subRows.first)
1216 row = row.subRows.first;
1219 for(; row; row = row.parent)
1221 if(row.next) { row = row.next; break; }
1226 OnResize(clientSize.w, clientSize.h);
1235 Clear(); // Ensure data is cleared first
1236 while((field = fields.first))
1241 endBevel.visible = false;
1246 void RemoveField(DataField field)
1252 int index = field.index;
1255 if(sortField == field)
1258 for(row = rows.first; row; )
1263 for(cell = row.cells.first, c = 0; c < index && cell; c++, cell = cell.next);
1264 if(cell && index == c)
1268 // TOCHECK: Is this check good? Will need incref/decref sometime?
1269 if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
1271 if(cell.data[0] && field.freeData)
1272 ((void (*)(void *, void *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnFree])(field.dataType, cell.data[0]);
1275 ((void (*)(void *, void *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnFree])(field.dataType, cell.data);
1278 row.cells.Remove(cell);
1282 if(row.subRows.first)
1283 row = row.subRows.first;
1286 for(; row; row = row.parent)
1288 if(row.next) { row = row.next; break; }
1297 endBevel.visible = false;
1301 DataRow AddRowNone()
1303 DataRow row { noneRow = true };
1310 rows.Insert(null, row);
1313 for(search = row.GetNextRow(); search; search = search.GetNextRow())
1319 firstRowShown = row;
1323 (rowCount * rowHeight) +
1324 ((style.header) ? rowHeight : 0) -
1325 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1326 if(style.autoScroll)
1327 SetScrollPosition(0, MAXINT - rowHeight);
1328 modifiedDocument = true;
1347 // Find very last row
1350 for(lastRow = rows.last; lastRow && !lastRow.collapsed && lastRow.subRows.last; lastRow = lastRow.subRows.last);
1351 row.index = lastRow ? (lastRow.index + 1) : 0;
1359 for(c = 0; c<fields.count; c++)
1361 for(field = fields.first; field; field = field.next)
1362 if((int)field.index == c)
1366 int size = (field.dataType && field.dataType.typeSize) ?
1367 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1368 ListBoxCell cell = (ListBoxCell) new0 byte[size];
1369 row.cells.Add(cell);
1370 FillBytes(cell.data, 0, size - (uint)(uintptr)&((ListBoxCell)0).data);
1377 firstRowShown = row;
1383 (rowCount * rowHeight) +
1384 ((style.header) ? rowHeight : 0) -
1385 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1386 if(style.autoScroll)
1387 SetScrollPosition(0, MAXINT - rowHeight);
1388 modifiedDocument = true;
1399 DataRow AddRowAfter(DataRow after)
1411 if(after && after.subRows.first && !after.collapsed)
1413 for(search = after.subRows.last; !search.collapsed && search.subRows.last; )
1414 search = search.subRows.last;
1415 row.index = search.index + 1;
1418 row.index = after ? (after.index + 1) : 0;
1419 rows.Insert(after, row);
1422 for(search = row.GetNextRow(); search; search = search.GetNextRow())
1427 for(c = 0; c<fields.count; c++)
1429 for(field = fields.first; field; field = field.next)
1430 if((int)field.index == c)
1434 int size = (field.dataType && field.dataType.typeSize) ?
1435 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1436 ListBoxCell cell = (ListBoxCell) new0 byte[size];
1437 row.cells.Add(cell);
1438 FillBytes(cell.data, 0, size - (uint)(uintptr)&((ListBoxCell)0).data);
1442 if(!firstRowShown || !after)
1444 firstRowShown = row;
1449 (rowCount * rowHeight) +
1450 ((style.header) ? rowHeight : 0) -
1451 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1452 if(style.autoScroll)
1453 SetScrollPosition(0, MAXINT - rowHeight);
1454 modifiedDocument = true;
1464 DataRow AddStringf(const char * format, ...)
1470 char string[MAX_F_STRING];
1473 va_start(args, format);
1474 vsnprintf(string, sizeof(string), format ? format : "", args);
1475 string[sizeof(string)-1] = 0;
1479 row.SetData(fields.first, string);
1485 DataRow AddString(const char * string)
1491 row.SetData(fields.first, string);
1497 void SelectRow(DataRow row)
1499 SetCurrentRow(row, true);
1502 void DeleteRow(DataRow row)
1504 if(!row) row = currentRow;
1507 DataRow sub, next, search;
1508 // Trying to move this here (Messed up deleting watches)
1509 //HideEditBox(false, false, true);
1512 for(sub = row.subRows.first; sub; sub = next)
1518 if(row.parent.IsExpanded())
1520 for(search = row.GetNextRow(); search; search = search.GetNextRow())
1525 HideEditBox(false, false, true);
1527 if(row == clickedRow)
1529 clickedRow = row.GetNextRow();
1531 clickedRow = row.GetPrevRow();
1534 if(row == currentRow)
1536 DataRow newCurrentRow = row.GetNextRow();
1538 newCurrentRow = row.GetPrevRow();
1539 SetCurrentRow(newCurrentRow, true);
1542 if(row == firstRowShown)
1544 firstRowShown = row.GetPrevRow();
1546 firstRowShown = row.GetNextRow();
1549 (row.parent ? row.parent.subRows: rows).Remove(row);
1552 //HideEditBox(false, false, true);
1556 (rowCount * rowHeight) +
1557 ((style.header) ? rowHeight : 0) -
1558 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1560 modifiedDocument = true;
1569 DataRow FindRow(int64 tag)
1574 for(row = rows.first; row; row = row.next)
1576 if(!row.noneRow && row.tag == tag)
1584 DataRow FindString(const char * searchedString)
1587 bool checkNextField = true;
1589 for(field = fields.first; field; field = field.next)
1591 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1594 for(row = rows.first; row; row = row.GetNextRow())
1598 void * data = row.GetData(field);
1599 char tempString[1024] = "";
1600 bool needClass = false;
1601 const char * string = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, data, tempString, null, &needClass);
1603 if(string && string[0])
1604 checkNextField = false;
1605 if(string && string[0] && !strcmp(string, searchedString))
1610 if(!checkNextField) break;
1615 DataRow FindSubString(const char * subString)
1618 bool checkNextField = true;
1619 int len = subString ? strlen(subString) : 0;
1623 for(field = fields.first; field; field = field.next)
1625 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1628 for(row = rows.first; row; row = row.GetNextRow())
1632 void * data = row.GetData(field);
1633 char tempString[1024] = "";
1634 bool needClass = false;
1635 const char * string = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, data, tempString, null, &needClass);
1637 if(string && string[0])
1638 checkNextField = false;
1639 if(string && string[0] && !strncmp(string, subString, len))
1644 if(!checkNextField) break;
1650 DataRow FindSubStringi(const char * subString)
1653 bool checkNextField = true;
1654 int len = subString ? strlen(subString) : 0;
1655 DataRow result = null;
1656 const char * bestResult = null;
1661 for(field = fields.first; field; field = field.next)
1663 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1666 for(row = rows.first; row; row = row.GetNextRow())
1670 void * data = row.GetData(field);
1671 char tempString[1024] = "";
1672 bool needClass = false;
1673 const char * string = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, data, tempString, null, &needClass);
1675 if(string && string[0])
1676 checkNextField = false;
1677 if(string && string[0])
1679 int stringLen = strlen(string);
1681 if(!strnicmp(string, subString, Min(len, stringLen)))
1683 if(bestLen < Min(len, stringLen))
1685 if(!bestResult || strcmpi(string, bestResult) < 0)
1687 bestLen = Min(len, stringLen);
1688 bestResult = string;
1696 if(!checkNextField) break;
1702 DataRow FindSubStringAfter(DataRow after, const char * subString)
1705 bool checkNextField = true;
1706 int len = subString ? strlen(subString) : 0;
1710 for(field = fields.first; field; field = field.next)
1712 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1715 for(row = after.GetNextRow(); row && row != after; row = row.GetNextRow(), (!row) ? (row = rows.first) : null)
1719 void * data = row.GetData(field);
1720 char tempString[1024] = "";
1721 bool needClass = false;
1722 const char * string = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, data, tempString, null, &needClass);
1724 if(string && string[0])
1725 checkNextField = false;
1726 if(string && string[0] && !strncmp(string, subString, len))
1731 if(!checkNextField) break;
1737 DataRow FindSubRow(int64 tag)
1743 for(row = rows.first; row; row = row.next)
1745 if(!row.noneRow && row.tag == tag)
1747 if(!row.noneRow && row.subRows.first)
1749 DataRow subRow = row.FindSubRow(tag);
1763 Window master = this.master;
1765 HideEditBox(false, true, false);
1766 editData.Destroy(0);
1768 firstRowShown = currentRow = null;
1773 if(style.freeSelect)
1774 NotifyHighlight(master, this, currentRow ? currentRow : null, 0);
1776 NotifySelect(master, this, currentRow ? currentRow : null, 0);
1779 if(style.alwaysEdit && currentRow)
1780 currentRow.Edit(currentField);
1787 (rowCount * rowHeight) +
1788 ((style.header) ? rowHeight : 0) -
1789 ((rowHeight && !((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1794 void Sort(DataField field, int order)
1799 int headerSize = ((style.header) ? rowHeight : 0);
1800 int height = clientSize.h + 1 - headerSize;
1802 if(!field) field = fields.first;
1804 field.sortOrder = order ? order : 1;
1805 rows.Sort(DataRow::Compare, field);
1807 for(search = rows.first; search; search = search.next)
1808 search._SortSubRows(field, order);
1812 for(search = rows.first; search; search = search.GetNextRow())
1813 search.index = index++;
1816 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
1817 SetScrollPosition(scroll.x, currentRow.index * rowHeight - height + rowHeight);
1818 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
1819 SetScrollPosition(scroll.x, currentRow ? currentRow.index * rowHeight : 0);
1821 OnVScroll(0, scroll.y, 0);
1823 // SetScrollPosition(0, scroll.y);
1828 void StopEditing(bool save)
1830 HideEditBox(save, false, true);
1833 void GetMultiSelection(OldList list)
1836 if(this && style.multiSelect)
1840 for(row = rows.first; row; row = row.GetNextRow())
1842 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
1844 list.Add(OldLink { data = row });
1850 // Convenience Current Row Methods
1851 void * SetData(DataField field, any_object data)
1853 return currentRow.SetData(field, data);
1856 any_object GetData(DataField field)
1858 return (void *)currentRow.GetData(field);
1863 return currentRow ? currentRow.tag : 0;
1869 DataField defaultField { };
1870 rows.offset = (uint)(uintptr)&((DataRow)0).prev;
1871 fields.offset = (uint)(uintptr)&((DataField)0).prev;
1872 style.fullRowSelect = true;
1873 style.fillLastField = true;
1874 style.expandOnAdd = true;
1875 typingTimeOut = 0.5;
1876 rowHeight = 16; // Stuff depending on creation and default property checking
1879 defaultField.defaultField = true;
1881 AddField(defaultField);
1883 typedString = new char[1];
1884 typedString[0] = '\0';
1899 while((field = fields.first))
1901 // fields.Remove(field);
1911 while((row = rows.first))
1918 ListBoxCell GetCell(DataRow * row, DataField * field)
1920 ListBoxCell cell = null;
1921 if(!*row) *row = currentRow;
1924 if(!*field) *field = this ? currentField : null;
1927 for(*field = fields.first; (*field).index != 0; *field = (*field).next);
1932 if(field->listBox == this)
1934 for(index = 0, cell = (*row).cells.first; cell && index != (*field).index; index++, cell = cell.next);
1941 void HideEditBox(bool save, bool alwaysStopEdit, bool repositionOnly)
1943 if(editData && editData.visible)
1946 editData.SaveData();
1948 editData.visible = false;
1949 NotifyEditDone(master, this, currentRow);
1951 // ENSURE DATA BOX IS NOT VISIBLE
1952 editData.visible = false;
1954 if(style.alwaysEdit && !alwaysStopEdit)
1957 int height = rowHeight - (style.alwaysEdit ? 1 : 0);
1958 int y = currentRow.index * rowHeight + (style.header ? rowHeight : 0);
1959 int x = currentField.x;
1960 int width = (!currentField.next && style.fillLastField && (!hasHorzScroll || clientSize.w - currentField.x > currentField.width + EXTRA_SPACE)) ?
1961 clientSize.w - currentField.x : (currentField.width + EXTRA_SPACE);
1963 if(!style.alwaysEdit)
1965 editData.position = { x, y };
1966 editData.size = { width, height };
1970 editData.position = { x, y - editData.clientStart.y };
1971 editData.size = { width, height + editData.clientStart.y * 2 };
1973 editData.visible = true;
1974 if(style.alwaysEdit)
1975 editData.Deactivate();
1977 PopupEditBox(currentField, repositionOnly);
1981 currentField = null;*/
1985 void SetCurrentRow(DataRow row, bool notify)
1987 if(this && (currentRow != row || (currentRow && currentRow.selectedFlag == unselected)))
1989 int headerSize = ((style.header) ? rowHeight : 0);
1990 int height = clientSize.h + 1 - headerSize;
1992 // true: destroy edit box
1993 HideEditBox(true, true, false);
1995 if(!(style.multiSelect) && currentRow)
1996 currentRow.selectedFlag = unselected;
2000 if(style.multiSelect)
2004 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
2005 selRow.selectedFlag = unselected;
2007 currentRow.selectedFlag = selected;
2012 currentRow.selectedFlag = selected;
2014 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
2015 SetScrollPosition(scroll.x,
2016 currentRow.index * rowHeight - height + rowHeight);
2017 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
2019 int line = currentRow ? currentRow.index * rowHeight : 0;
2020 //SNAPUP(line, rowHeight);
2021 SetScrollPosition(scroll.x, line);
2026 Window master = this.master;
2029 if(style.freeSelect && visible)
2030 NotifyHighlight(master, this, currentRow ? currentRow : null, 0);
2032 NotifySelect(master, this, currentRow ? currentRow : null, 0);
2033 if(style.alwaysEdit && currentRow)
2034 currentRow.Edit(currentField);
2042 void RepositionFieldEditor()
2044 if(editData && editData.visible)
2046 int height = rowHeight - (style.alwaysEdit ? 1 : 0);
2048 int y = currentRow.index * rowHeight + (style.header ? rowHeight : 0);
2052 if(style.collapse && !(style.treeBranch))
2054 for(field = fields.first; field; field = field.next)
2056 width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2057 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2058 if(field == currentField) break;
2061 if(!style.alwaysEdit)
2063 editData.position = { x, y - editData.clientStart.y };
2064 editData.size = { width, height + editData.clientStart.y * 2 };
2068 editData.position = { x, y };
2069 editData.size = { width, height };
2074 void PopupEditBox(DataField whichField, bool repositionOnly)
2076 if((!editData || !editData.visible || currentField != whichField) && currentRow)
2078 // true: destroy edit box
2079 HideEditBox(true, true, false);
2082 int height = rowHeight - (style.alwaysEdit ? 1 : 0);
2084 int y = currentRow.index * rowHeight + (style.header ? rowHeight : 0);
2086 //void * data = currentRow.GetData(whichField);
2091 if(style.collapse && !(style.treeBranch))
2094 for(field = fields.first; field; field = field.next)
2096 width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2097 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2098 if(field == whichField) break;
2102 currentField = whichField;
2103 cell = GetCell(&row, ¤tField);
2110 background = dataBoxBackground;
2111 foreground = dataBoxForeground;
2113 bool NotifyChanged(DataBox dataBox, bool closingDropDown)
2116 DataField field = null;
2117 ListBoxCell cell = GetCell(&row, &field);
2121 modifiedDocument = true;
2123 NotifyChanged(master, this, currentRow);
2128 bool NotifyModified()
2130 //DataRow row = null;
2131 //DataField field = null;
2132 //ListBoxCell cell = GetCell(&row, &field);
2133 //cell.isSet = true;
2134 modifiedDocument = true;
2136 NotifyModified(master, this, currentRow);
2140 bool OnKeyDown(Key key, unichar ch)
2142 bool result = DataBox::OnKeyDown(key, ch);
2143 if(visible && active) // Added this check here, because we will not use enter/escape otherwise, and lose DataBox's result
2145 if((SmartKey)key == enter || (SmartKey)key == escape)
2154 editData.Destroy(0);
2155 editData.type = whichField.dataType;
2156 editData.fieldData = whichField.userData;
2157 editData.borderStyle = style.alwaysEdit ? 0 : deep;
2158 editData.data = cell ? cell.data : null;
2161 // Might not really need this anymore...
2162 NotifyEditing(master, this, currentRow);
2165 if(!style.alwaysEdit)
2167 editData.position = { x, y - editData.clientStart.y };
2168 editData.size = { width, height + editData.clientStart.y * 2 };
2172 editData.position = { x, y };
2173 editData.size = { width, height };
2177 editData.visible = true;
2179 if(style.alwaysEdit)
2180 editData.Deactivate();
2182 // MOVED THIS HIGHER FOR DATALIST EDITOR
2184 // Might not really need this anymore...
2185 NotifyEdited(master, this, currentRow);
2190 void OnRedraw(Surface surface)
2193 int y = (style.header) ? rowHeight : 0;
2194 bool isActive = active;
2195 Font font = fontObject;
2196 Font boldFont = this.boldFont.font;
2199 if(style.alwaysEdit && style.fullRowSelect)
2202 int y = (style.header) ? rowHeight : 0;
2203 int x = -scroll.x - 1;// + EXTRA_SPACE;// / 2 - 1;
2204 int w = clientSize.w;
2205 int h = clientSize.h;
2209 // Fill out indent column
2210 if(style.collapse && !(style.treeBranch) && (style.header || rows.first))
2213 surface.SetBackground(formColor);
2214 surface.Area(-scroll.x, 0, x, clientSize.h);
2217 surface.SetForeground(formColor);
2218 for(row = firstRowShown; row; row = row.GetNextRow())
2221 surface.HLine(x + 1, w-1, y-1);
2227 for(field = fields.first; field; field = field.next)
2229 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2230 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2231 if(field.prev && y > 0)
2232 surface.VLine(0, y-1, x);
2237 surface.foreground = this.foreground;
2238 surface.TextOpacity(false);
2240 // Draw the tree branches
2241 if(style.treeBranch)
2243 int y = -scroll.y + ((style.header) ? rowHeight : 0);
2244 surface.LineStipple(0x5555);
2245 surface.SetForeground(branchesColor);
2246 for(row = rows.first; row; row = row.GetNextRow() )
2248 int x = -scroll.x + EXTRA_SPACE / 2-1;
2249 int rowStart = -scroll.x;
2254 for(parent = row.parent; parent; parent = parent.parent)
2255 if(!parent.header) indent += 20;
2256 if(style.rootCollapse) indent += 20;
2258 plusIndent = (style.treeBranch) ? (indent - 20 + 4) : indent;
2263 if(row.subRows.first)
2266 int y1 = y + PLUSY + 4;
2270 for(child = row.collapsed ? null : row.subRows.first; child && child != row; )
2273 if(child.subRows.first && !child.collapsed && child != row.subRows.last)
2274 child = child.subRows.first;
2279 for(; child && child != row; child = child.parent)
2289 y2 = y + numRows * rowHeight + PLUSY + 4;
2290 surface.VLine(y1, y2, rowStart + plusIndent + 7 + 20);
2292 surface.HLine(rowStart + plusIndent + 7, rowStart + indent, y + PLUSY + 4);
2295 if(y >= clientSize.h)
2298 // Root Vertical Lines
2299 if(style.rootCollapse && rows.first)
2304 y = -scroll.y + ((style.header) ? rowHeight : 0);
2306 for(child = rows.first; child && child != rows.last; )
2309 if(child.subRows.first && !child.collapsed && child != rows.last)
2310 child = child.subRows.first;
2315 for(; child; child = child.parent)
2325 y2 = y + numRows * rowHeight + PLUSY + 4;
2326 surface.VLine(y1, y2, -scroll.x + 11);
2328 surface.LineStipple(0);
2331 for(row = firstRowShown; row; row = row.GetNextRow() )
2333 int x = -scroll.x + EXTRA_SPACE / 2-1;
2336 Color foreground = this.foreground /*black*/, background = this.background /*white*/;
2337 DataDisplayFlags dataDisplayFlags = 0;
2338 int rowStart = -scroll.x;
2341 Bitmap icon = row.icon ? row.icon.bitmap : null;
2342 int collapseRowStart = 0;
2343 bool lastWasHeader = row.header;
2345 for(parent = row.parent; parent; parent = parent.parent)
2347 if(!parent.header || lastWasHeader)
2349 if(style.treeBranch)
2355 if(style.rootCollapse) indent += 20;
2358 dataDisplayFlags.fullRow = style.fullRowSelect;
2359 dataDisplayFlags.active = isActive;
2360 dataDisplayFlags.header = row.header;
2365 collapseRowStart = rowStart;
2367 if(!(style.treeBranch))
2374 if(style.multiSelect)
2376 dataDisplayFlags.selected = row.selectedFlag == selected || row.selectedFlag == tempSelected;
2377 dataDisplayFlags.current = row == currentRow || (!currentRow && row == firstRowShown);
2381 dataDisplayFlags.selected = row.selectedFlag == selected || row.selectedFlag == tempSelected;
2382 dataDisplayFlags.current = row == currentRow || (!currentRow && row == firstRowShown);
2384 if(row == currentRow)
2386 dataDisplayFlags.current = true;
2387 dataDisplayFlags.selectedFlag = true;
2389 else if(!currentRow && row == firstRowShown)
2391 dataDisplayFlags.current = true;
2395 surface.TextOpacity(true);
2397 background = this.background;
2398 foreground = this.foreground;
2400 // Draw the current row background
2403 Color colors[] = { formColor, azure, mistyRose, linen, floralWhite, lavender, lavenderBlush, lemonChiffon };
2406 while((p = p.parent)) level++;
2407 background = colors[level % (sizeof(colors)/sizeof(colors[0]))];
2408 surface.SetBackground(background);
2409 surface.Area(rowStart, y, clientSize.w, (y + rowHeight) - 1);
2410 foreground = branchesColor;
2412 else if(dataDisplayFlags.selected)
2414 if(dataDisplayFlags.selected && (isActive || style.alwaysHL || (style.alwaysEdit && style.fullRowSelect)))
2416 if(!isActive && style.alwaysEdit)
2417 background = formColor;
2419 background = selectionColor ? selectionColor : SELECTION_COLOR;
2420 if(style.fullRowSelect)
2422 int offset = (style.alwaysEdit) ? 2 : 1;
2423 surface.SetBackground(background);
2424 surface.Area(rowStart, y, clientSize.w, (y + rowHeight) - offset);
2426 if(isActive || !(style.alwaysEdit))
2427 foreground = selectionText ? selectionText : SELECTION_TEXT;
2429 foreground = branchesColor;
2435 surface.Blit(icon, x + (20 - icon.width) /2,y + 2,0,0, icon.width, icon.height);
2441 int width = clientSize.w;
2443 dataDisplayFlags.firstField = true;
2444 clip.left = x - EXTRA_SPACE / 2+1;
2446 clip.right = x + width - EXTRA_SPACE/2 - 0;
2447 clip.bottom = y + rowHeight - 1;
2448 surface.Clip(&clip);
2450 surface.TextFont(font);
2452 surface.SetForeground(foreground);
2453 surface.SetBackground(background);
2455 ((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);
2459 if(opacity < 1) surface.TextOpacity(false);
2461 for(field = fields.first; field; field = field.next)
2464 int width = ((!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) || row.header) ?
2465 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2467 // Box clip = { x, y+1, x + field.width - EXTRA_SPACE - 1, y + rowHeight - 2 };
2470 //width -= EXTRA_SPACE;
2472 if(!field.prev) width -= indent;
2475 dataDisplayFlags.firstField = field.prev ? false : true;
2477 if(!dataDisplayFlags.firstField && !dataDisplayFlags.fullRow)
2479 background = this.background;
2480 foreground = this.foreground;
2483 if(!isActive && dataDisplayFlags.selected && style.alwaysEdit && field.editable && opacity)
2486 surface.SetBackground(background);
2487 surface.Area(x-3, y, x+width-1, y + rowHeight-2);
2490 clip.left = x - EXTRA_SPACE / 2+1;
2492 clip.right = x + width - EXTRA_SPACE/2 - 0;
2493 clip.bottom = y + rowHeight - 1;
2494 surface.Clip(&clip);
2496 for(index = 0, cell = row.cells.first; cell && index != field.index; index++, cell = cell.next);
2497 // Should always be as many cells in the row as fields in the listbox
2498 if(cell && cell.isSet && field.dataType)
2501 surface.TextFont(boldFont);
2503 surface.TextFont(font);
2505 surface.SetForeground(foreground);
2506 surface.SetBackground(background);
2508 if(field.dataType.type == noHeadClass || field.dataType.type == normalClass)
2509 ((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);
2511 ((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);
2514 if(!isActive && dataDisplayFlags.selected && style.alwaysEdit && field.editable)
2515 background = formColor;
2517 if(!dataDisplayFlags.firstField && !dataDisplayFlags.fullRow)
2519 background = formColor;
2520 foreground = this.background;
2524 // surface.WriteTextf(x + 100, y, "ix: %d", row.index);
2527 x += width;// + EXTRA_SPACE;
2529 if(row.header) break;
2535 int plusIndent = (style.treeBranch) ? (indent - 20 + 4) : indent;
2537 if(row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)))
2539 surface.SetForeground(row.header ? headerCollapseForeground : this.foreground);
2540 surface.Rectangle(collapseRowStart + 3 + plusIndent, y + PLUSY, collapseRowStart + 11 + plusIndent, y + PLUSY + 8);
2542 surface.SetBackground(row.header ? (formColor) : (this.background)); //white
2543 surface.Area(collapseRowStart + 4 + plusIndent, y + PLUSY + 1, collapseRowStart + 10 + plusIndent, y + PLUSY + 7);
2545 surface.HLine(collapseRowStart + 5 + plusIndent, collapseRowStart + 9 + plusIndent, y+PLUSY+4);
2547 surface.VLine(y + PLUSY + 2, y + PLUSY + 6, collapseRowStart + 7 + plusIndent);
2552 // Draw the current row stipple
2553 if(style.fullRowSelect && !(style.alwaysEdit) && (dataDisplayFlags.current) && isActive)
2558 surface.LineStipple(0x5555);
2559 if(dataDisplayFlags.selected)
2560 surface.SetForeground(stippleColor);
2562 surface.SetForeground(this.foreground);
2565 surface.SetForeground(selectionColor ? selectionColor : SELECTION_COLOR);
2566 surface.Rectangle(0, y, clientSize.w-1, (y + rowHeight) - 1);
2567 surface.LineStipple(0);
2571 if(y >= clientSize.h)
2574 if(firstRowShown) surface.Clip(null);
2575 if(dragRow && dropIndex != -1)
2580 if(!style.multiSelect && currentRow.index < dropIndex)
2582 surface.DrawingChar(223);
2584 y = style.header ? rowHeight : 0;
2585 y += ix * rowHeight - scroll.y;
2587 surface.SetForeground(Color { 85, 85, 255 });
2588 surface.HLine(0, clientSize.w-1, y);
2589 surface.HLine(0, clientSize.w-1, y + 1);
2593 void OnDrawOverChildren(Surface surface)
2595 if(draggingField && dropField)
2597 int position = dropField.x;
2598 if(draggingField.x < position)
2599 position += dropField.width + EXTRA_SPACE;
2601 surface.SetForeground(Color { 85, 85, 255 });
2602 surface.VLine(0, rowHeight - 1, position - scroll.x - 2);
2603 surface.VLine(0, rowHeight - 1, position - scroll.x);
2605 if(sortField && !style.clearHeader && style.header)
2607 DataField field = sortField;
2608 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2609 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2612 surface.TextExtent(field.header, strlen(field.header), &tw, &th);
2613 if(tw < width - EXTRA_SPACE)
2615 bool up = field.sortOrder == 1;
2619 field.x + 2 - scroll.x, 0,
2620 field.x + width + EXTRA_SPACE - 1 - scroll.x, rowHeight
2622 surface.Clip(&clip);
2623 if(field.alignment == left || field.alignment == center)
2625 if(field.alignment == center)
2626 x = field.x + (width + EXTRA_SPACE - tw) / 2 + tw + EXTRA_SPACE + 4;
2628 x = field.x + tw + EXTRA_SPACE + 4;
2630 x = Min(x, field.x + width - 4);
2632 else if(field.alignment == right)
2634 x = field.x + width - tw - 2*EXTRA_SPACE - 4;
2635 x = Max(x, field.x + 2);
2641 // surface.SetForeground((wmenu.selectedFlag == item) ? white : black);
2642 // surface.WriteText(clientSize.w-8, y+(wmenu.rh - 8)/2, "\020", 1);
2648 surface.SetForeground(Color { 128,128,128 } );
2649 surface.DrawLine(x + 3, y, x, y + 5);
2650 surface.PutPixel(x + 1, y + 5);
2651 surface.PutPixel(x + 1, y + 3);
2652 surface.PutPixel(x + 2, y + 1);
2654 surface.SetForeground(white);
2655 surface.DrawLine(x + 4, y, x + 7, y + 5);
2656 surface.PutPixel(x + 6, y + 5);
2657 surface.PutPixel(x + 6, y + 3);
2658 surface.PutPixel(x + 5, y + 1);
2660 surface.DrawLine(x, y + 6, x + 7, y + 6);
2664 surface.SetForeground(Color { 128,128,128 });
2665 surface.DrawLine(x + 3, y+6, x, y+1);
2666 surface.PutPixel(x + 1, y+1);
2667 surface.PutPixel(x + 1, y+3);
2668 surface.PutPixel(x + 2, y+5);
2670 surface.SetForeground(white);
2671 surface.DrawLine(x + 4, y+6, x + 7, y+1);
2672 surface.PutPixel(x + 6, y+1);
2673 surface.PutPixel(x + 6, y+3);
2674 surface.PutPixel(x + 5, y+5);
2676 surface.DrawLine(x, y, x + 7, y);
2685 void OnResize(int w, int h)
2688 bool showEndBevel = false;
2690 if(style.collapse && !style.treeBranch)
2692 for(field = fields.first; field; field = field.next)
2694 int width = field.width + EXTRA_SPACE;
2702 (rowCount * rowHeight) +
2703 ((style.header) ? rowHeight : 0) -
2704 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
2706 for(field = fields.first; field; field = field.next)
2708 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2709 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2710 if(style.header && field.headButton)
2712 showEndBevel = true;
2715 field.headButton.position = { field.x, 0 };
2716 field.headButton.size = { width, rowHeight };
2717 field.headButton.visible = true;
2720 field.headButton.visible = false;
2724 if(!style.fillLastField && showEndBevel && endBevel)
2726 endBevel.position = { x, 0 };
2727 endBevel.size = { clientSize.w + 2 - x, rowHeight };
2728 endBevel.visible = true;
2731 endBevel.visible = false;
2733 if(style.alwaysEdit && editData && editData.visible)
2735 HideEditBox(true, false, true);
2737 else if(editData && editData.visible)
2738 RepositionFieldEditor();
2741 void AdaptToFieldWidth(DataField field, bool doScroll)
2743 OnResize(clientSize.w, clientSize.h);
2745 // Scroll appropriately
2748 if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x &&
2749 field.x >= field.x + field.width + EXTRA_SPACE - clientSize.w)
2751 SetScrollPosition(field.x + field.width + EXTRA_SPACE - clientSize.w, scroll.y);
2753 else if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x ||
2755 SetScrollPosition(field.x, scroll.y);
2760 bool HeaderPushed(Button control, int x, int y, Modifiers mods)
2762 DataField field = (DataField)(intptr)control.id;
2763 // false: dont destroy edit box
2764 HideEditBox(true, false, true);
2765 if(style.resizable && ((!field && x < RESIZE_BORDER && fields.last) ||
2766 (field && x < RESIZE_BORDER && field.prev) ||
2767 (field && x >= control.clientSize.w - RESIZE_BORDER)))
2770 field = fields.last;
2771 else if(x < RESIZE_BORDER && field.prev)
2774 if(field.fixed) return false;
2775 resizingField = field;
2776 resizeX = x + control.position.x;
2777 startWidth = field.width;
2778 oldX = x - scroll.x;
2783 if(field.fixed) return false;
2784 draggingField = field;
2785 if(style.moveFields)
2786 field.headButton.stayDown = true;
2787 else if(!style.sortable)
2795 bool HeaderMouseMove(Button control, int x, int y, Modifiers mods)
2800 DataField field = resizingField;
2802 x += control.position.x;
2804 // Tweak to prevent shrinking field if we're actually moving right
2805 if(x - scroll.x > oldX &&
2806 startWidth + x - resizeX < field.width)
2808 oldX = x - scroll.x;
2811 oldX = x - scroll.x;
2813 field.width = startWidth + x - resizeX;
2814 field.width = Max(field.width, - EXTRA_SPACE);
2816 AdaptToFieldWidth(field, true);
2818 else if(draggingField)
2820 x += control.position.x;
2821 if(style.moveFields)
2823 DataField field = fields.last;
2825 for(field = fields.first; field; field = field.next)
2827 fieldX += ((field.width || style.resizable) ?
2828 field.width : clientSize.w) + EXTRA_SPACE;
2832 if(draggingField == field)
2834 // Reset scroll position
2835 if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x &&
2836 field.x >= field.x + field.width + EXTRA_SPACE - clientSize.w)
2839 field.x + field.width + EXTRA_SPACE - clientSize.w,
2842 else if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x ||
2844 SetScrollPosition(field.x, scroll.y);
2847 if(dropField != field)
2852 int position = field.x;
2854 if(draggingField.x < position)
2856 position += field.width + EXTRA_SPACE - clientSize.w;
2857 if(position > scroll.x)
2858 SetScrollPosition(position, scroll.y);
2863 if(position < scroll.x)
2864 SetScrollPosition(position, scroll.y);
2867 movingFields = true;
2873 else if(style.resizable)
2875 DataField field = (DataField)(intptr)control.id;
2878 if(x < RESIZE_BORDER && field.prev)
2880 if(!field.prev.fixed)
2881 control.cursor = guiApp.GetCursor(sizeWE);
2883 else if(x >= control.clientSize.w - RESIZE_BORDER)
2884 control.cursor = guiApp.GetCursor(sizeWE);
2886 control.cursor = null;
2890 if(x < RESIZE_BORDER && fields.last)
2891 control.cursor = guiApp.GetCursor(sizeWE);
2893 control.cursor = null;
2899 bool HeaderReleased(Button control, int x, int y, Modifiers mods)
2903 NotifyResized(master, this, resizingField, mods);
2904 resizingField = null;
2911 if(style.moveFields)
2916 DataField switchField = fields.last;
2920 x += draggingField.x;
2921 for(field = fields.first; field; field = field.next)
2923 fieldX += ((field.width || style.resizable) ?
2924 field.width : clientSize.w) + EXTRA_SPACE;
2927 switchField = field;
2931 if(switchField && draggingField != switchField && dropField)
2933 for(field = fields.first; field; field = field.next)
2935 if(field == switchField || field == draggingField)
2939 // Switch field first: move before
2940 if(field == switchField)
2941 draggingField.Move(switchField.prev);
2942 // Dragged field first: move after
2944 draggingField.Move(switchField);
2946 NotifyMovedField(master, this, draggingField, mods);
2948 draggingField.headButton.stayDown = false;
2953 movingFields = false;
2955 draggingField = null;
2961 bool HeaderClicked(Button control, int x, int y, Modifiers mods)
2963 if(style.header && !dropField && style.sortable)
2965 DataField field = (DataField)(intptr)control.id;
2966 if(sortField == field)
2967 field.sortOrder *= -1;
2972 Sort(sortField, field.sortOrder);
2973 NotifySort(master, this, field, mods);
2979 bool HeaderDoubleClicked(Button control, int x, int y, Modifiers mods)
2983 DataField field = (DataField)(intptr)control.id;
2986 if(x < RESIZE_BORDER && field.prev)
2988 else if(x >= control.clientSize.w - RESIZE_BORDER);
2994 if(x < RESIZE_BORDER && fields.last)
2995 field = fields.last;
3007 if(style.freeSelect)
3012 rolledOver = dragging = false;
3019 bool OnLoadGraphics()
3021 display.FontExtent(fontObject, "W", 1, null, &fontH);
3022 if(!style.heightSet)
3024 rowHeight = Max(fontH + 2, 16) + (style.alwaysEdit ? 1 : 0);
3025 SetScrollLineStep(8, rowHeight);
3030 void OnApplyGraphics()
3032 SetScrollLineStep(8, rowHeight);
3036 for(field = fields.first; field; field = field.next)
3038 if(field.headButton)
3040 field.headButton.bevel = (!guiApp.textMode && !style.clearHeader);
3042 field.headButton.background = Color { 0, 170, 0 };
3046 OnResize(clientSize.w, clientSize.h);
3049 bool OnResizing(int *w, int *h)
3053 if(!initSize.w && (!anchor.left.type || !anchor.right.type) && !*w)
3058 Font font = fontObject;
3059 Font boldFont = this.boldFont.font;
3060 Display display = this.display;
3062 for(row = rows.first; row; row = row.GetNextRow())
3064 Bitmap icon = row.icon ? row.icon.bitmap : null;
3065 int x = -scroll.x + EXTRA_SPACE / 2-1;
3069 for(parent = row.parent; parent; parent = parent.parent)
3073 if(style.treeBranch)
3079 if(style.rootCollapse) indent += 20;
3081 if(style.collapse && !(style.treeBranch)) x += 15;
3085 // Compute the rows size
3086 for(field = fields.first; field; field = field.next)
3088 if(((style.resizable && (!(style.alwaysEdit) || field.next)) || field.width) && !row.header)
3089 x += field.width - (field.prev ? 0 : indent);
3094 for(index = 0, cell = row.cells.first; index != field.index; index++, cell = cell.next);
3096 // Should always be as many cells in the row as fields in the listbox
3097 if(cell && cell.isSet && field.dataType)
3099 static char tempString[4096];
3100 const char * string;
3102 if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
3103 string = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, cell.data[0], tempString, field.userData, null);
3105 string = ((const char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, cell.data, tempString, field.userData, null);
3107 if(!string) string = "";
3108 display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, &th);
3111 display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, &th);
3113 display.FontExtent(row.header ? boldFont : font, "", 0, &tw, &th);
3116 if(row.header) break;
3120 maxWidth = Max(maxWidth, x);
3126 *h = Min(maxShown, rowCount) * rowHeight;
3131 if(!*w) *w = rowHeight * 5;
3132 if(!*h) *h = rowHeight * 5;
3139 FontResource font = this.font;
3140 FontResource boldFont
3142 faceName = font.faceName, size = font.size, bold = true
3144 AddResource(boldFont);
3145 RemoveResource(this.boldFont);
3146 this.boldFont = boldFont;
3150 SetInitSize(initSize);
3153 bool OnMouseMove(int x, int y, Modifiers mods)
3155 bool isTimer = false;
3156 int realX = x, realY = y;
3158 if(insideNotifySelect) return true;
3160 if(style.alwaysEdit && style.resizable &&
3161 resizingField && !(mods.isSideEffect))
3164 DataField field = resizingField;
3165 field.width = startWidth + x - resizeX;
3166 field.width = Max(field.width, - EXTRA_SPACE);
3168 AdaptToFieldWidth(field, true);
3172 if(style.alwaysEdit && style.resizable)
3174 int vx = -scroll.x - 1;
3177 if(style.collapse && !(style.treeBranch))
3180 for(field = fields.first; field; field = field.next)
3182 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3183 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3189 cursor = guiApp.GetCursor(sizeWE);
3193 vx += width + EXTRA_SPACE;
3197 if((editData && editData.visible) || (style.alwaysEdit))
3200 if(x == MAXINT && y == MAXINT)
3207 // ADDED THIS CHECK FOR FieldDropBox LEAKS
3208 if(/*!mods.isSideEffect && */(rolledOver || !dragging))
3210 int rowY = (style.header) ? rowHeight : 0;
3211 DataRow row = null, nextRow;
3218 ((vertScroll && vertScroll.visible &&
3219 (y < 0 || y >= clientSize.h)) ||
3220 (horzScroll && horzScroll.visible &&
3221 (x < 0 || x >= clientSize.w))))
3226 if(vertScroll && vertScroll.visible &&
3227 (y < 0 || y >= clientSize.h))
3228 vertScroll.Action((y<0)?up:down, 0, 0);
3229 if(horzScroll && horzScroll.visible &&
3230 (x < 0 || x >= clientSize.w))
3231 horzScroll.Action((x<0)?up:down, 0, 0);
3237 // This must be done after the scrolling took place
3238 rowIndex = firstRowShown ? firstRowShown.index : -1;
3240 y = Min(y, clientSize.h - ((dragRow && style.moveRows) ? rowHeight : 0)-1);
3241 for(row = firstRowShown; row; row = nextRow, rowIndex ++)
3243 nextRow = row.GetNextRow();
3245 if(rowY > y || !nextRow)
3251 if(dragRow && style.moveRows)
3253 if(row && row == currentRow)
3254 row = row.GetNextRow();
3256 if(row && row.parent == currentRow)
3257 row = row.GetNextRow();
3260 if(row && currentRow != row)
3262 if(dragRow && style.moveRows)
3264 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
3266 else if(style.multiSelect)
3269 for(thisRow = rows.first; thisRow; thisRow = thisRow.GetNextRow())
3270 if((thisRow.selectedFlag == selected || thisRow.selectedFlag == tempSelected) ||
3276 if(dropIndex != rowIndex)
3278 dropIndex = rowIndex;
3284 else if((style.freeSelect || dragging) && ((realX>= 0 && realY >= 0 && realX< clientSize.w && realY < clientSize.h) || rolledOver))
3286 if(!(style.multiSelect))
3288 if(currentRow)currentRow.selectedFlag = unselected;
3289 if(row)row.selectedFlag = selected;
3293 if(style.multiSelect)
3297 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3299 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3300 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3303 if(rowIndex >= clickedRow.index)
3305 for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
3307 selRow.selectedFlag = (selRow.selectedFlag == selected) ? tempUnselected : tempSelected;
3314 for(selRow = row; selRow; selRow = selRow.GetNextRow())
3316 selRow.selectedFlag = (selRow.selectedFlag == selected) ? tempUnselected : tempSelected;
3317 if(selRow == clickedRow)
3323 if(style.freeSelect)
3324 NotifyHighlight(master, this, currentRow, mods);
3327 insideNotifySelect = true;
3328 NotifySelect(master, this, currentRow, mods);
3329 insideNotifySelect = false;
3332 if(style.alwaysEdit && currentRow)
3333 currentRow.Edit(currentField);
3340 bool OnMouseOver(int x, int y, Modifiers mods)
3347 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
3349 // TOCHECK: WAS THIS MISSING ? CHECK FOR SLOWDOWN
3350 if(!active) Update(null);
3352 if(!active && (!swap || !swap.isModal))
3354 // true: destroy edit box
3355 HideEditBox(true, true, false);
3357 else if(!swap || !swap.isModal)
3359 // Bring back edit box
3360 if(currentRow && style.alwaysEdit)
3362 currentRow.Edit(currentField ? currentField : null);
3366 return true; //NotifyActivate(master, this, active, swap, 0);
3370 bool OnButtonDown(int x, int y, Modifiers mods, bool right)
3373 // Check to see if we're dragging the vertical divider
3374 if(style.alwaysEdit && style.resizable && !right)
3376 int vx = -scroll.x - 1;// + EXTRA_SPACE;// / 2 - 1;
3379 if(style.collapse && !(style.treeBranch))
3382 for(field = fields.first; field; field = field.next)
3384 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3385 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3391 resizingField = field.prev;
3393 startWidth = resizingField.width;
3395 SetMouseRangeToClient();
3399 vx += width + EXTRA_SPACE;
3403 if(!(style.freeSelect))
3405 int rowY = (style.header) ? rowHeight : 0;
3407 int rowIndex = firstRowShown ? firstRowShown.index : -1;
3408 DataRow previousRow = currentRow;
3409 DataRow newCurrentRow = null;
3410 bool moveMultiple = false;
3411 int numSelected = 0;
3412 int rowStart = -scroll.x;
3414 if(style.multiSelect)
3421 for(row = rows.first; row; row = row.GetNextRow())
3423 if(row.selectedFlag == tempSelected)
3424 row.selectedFlag = selected;
3425 else if(row.selectedFlag == tempUnselected)
3426 row.selectedFlag = unselected;
3427 if(row.selectedFlag == selected)
3434 for(row = firstRowShown; row; row = row.GetNextRow(), rowIndex ++)
3437 if(rowY > y || (style.multiSelect && !row.GetNextRow()))
3440 if(style.treeBranch)
3443 for(parent = (style.rootCollapse) ? row.parent : (row.parent ? row.parent.parent : null); parent; parent = parent.parent)
3449 /* THIS WAS TOO STRICT:
3450 if(style.collapse && row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)) &&
3451 (x >= rowStart + 3 + plusIndent && y >= rowY - rowHeight + PLUSY && x <= rowStart + 11 + plusIndent && y <= rowY - rowHeight + PLUSY + 8))
3453 if(style.collapse &&
3454 (x >= rowStart && y >= rowY - rowHeight && x <= rowStart + 18 + plusIndent && y <= rowY + rowHeight-1))
3456 if(row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)) && x >= plusIndent)
3457 row.collapsed = !row.collapsed;
3464 newCurrentRow = row;
3466 if(style.multiSelect)
3468 // Deselect everything if user didn't clicked on a row
3472 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3473 selRow.selectedFlag = unselected;
3475 //clickedRowIndex = rowIndex;
3477 else if(style.moveRows && !(mods.shift) &&
3478 (row.selectedFlag == selected || row.selectedFlag == tempSelected) &&
3479 !right && !(mods.isActivate))
3480 moveMultiple = true;
3486 if(row.selectedFlag == tempUnselected || row.selectedFlag == unselected)
3488 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3489 selRow.selectedFlag = unselected;
3490 row.selectedFlag = selected;
3493 //clickedRowIndex = rowIndex;
3499 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3500 selRow.selectedFlag = unselected;
3504 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3506 if(selRow != clickedRow)
3508 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3509 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3516 if(rowIndex >= clickedRow.index)
3518 for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
3522 if(selRow != clickedRow)
3524 if(selRow.selectedFlag)
3525 selRow.selectedFlag = tempUnselected;
3527 selRow.selectedFlag = tempSelected;
3531 selRow.selectedFlag = selected;
3538 for(selRow = row; selRow; selRow = selRow.GetNextRow())
3542 if(selRow != clickedRow)
3544 if(selRow.selectedFlag)
3545 selRow.selectedFlag = tempUnselected;
3547 selRow.selectedFlag = tempSelected;
3551 selRow.selectedFlag = selected;
3552 if(selRow == clickedRow)
3561 if(row.selectedFlag)
3562 row.selectedFlag = tempUnselected;
3563 else row.selectedFlag = tempSelected;
3566 row.selectedFlag = tempSelected;
3568 //clickedRowIndex = rowIndex;
3578 // true: destroy edit box
3581 incref newCurrentRow;
3584 if(currentRow != newCurrentRow)
3585 HideEditBox(true, true, false);
3589 if(newCurrentRow._refCount <= 1)
3590 delete newCurrentRow;
3592 newCurrentRow._refCount--;
3597 if(!(style.multiSelect))
3599 if(currentRow) currentRow.selectedFlag = unselected;
3600 if(newCurrentRow) newCurrentRow.selectedFlag = selected;
3604 if(currentRow != newCurrentRow)
3607 // true: destroy edit box
3610 //incref newCurrentRow;
3611 incref newCurrentRow;
3614 HideEditBox(true, true, false);
3619 int headerSize = ((style.header) ? rowHeight : 0);
3620 int height = clientSize.h + 1 - headerSize;
3622 /*if(newCurrentRow._refCount <= 1)
3623 delete newCurrentRow;
3626 newCurrentRow._refCount--;
3627 //newCurrentRow._refCount--;
3630 currentRow = newCurrentRow;
3632 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
3633 SetScrollPosition(scroll.x,
3634 currentRow.index * rowHeight - height + rowHeight);
3635 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
3637 int line = currentRow ? currentRow.index * rowHeight : 0;
3638 //SNAPUP(line, rowHeight);
3639 SetScrollPosition(scroll.x, line);
3642 // GO THROUGH SetCurrentRow eventually?
3643 // SetCurrentRow(newCurrentRow, true);
3647 if(style.freeSelect)
3648 NotifyHighlight(master, this, currentRow, mods);
3649 else if((moveMultiple || (!(style.multiSelect) && previousRow == currentRow)) &&
3650 newCurrentRow && !(mods.shift))
3654 if(!(mods.isActivate))
3658 dragRow = currentRow;
3664 if(editData && editData.visible && style.alwaysEdit)
3671 if(style.collapse && !style.treeBranch)
3674 for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3676 indent += (style.treeBranch) ? 20 : 15;
3679 for(field = fields.first; field; field = field.next)
3681 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3682 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3684 if(!field.prev) width -= indent;
3685 if(x >= sx && x < sx + width)
3689 if(field == currentField)
3690 editData.Deactivate();
3693 currentRow.Edit(field);
3694 editData.Activate();
3697 else if(!(mods.ctrl) && numSelected <= 1)
3698 editRow = currentRow;
3700 if(style.noDragging && newCurrentRow)
3701 NotifyReclick(master, this, newCurrentRow, mods);
3705 // If the user clicked exactly on the edited field,
3707 if(editData && editData.visible && newCurrentRow)
3713 if(style.collapse && !(style.treeBranch))
3718 for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3720 indent += (style.treeBranch) ? 20 : 15;
3724 for(field = fields.first; field; field = field.next)
3726 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3727 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3728 if(!field.prev) width -= indent;
3729 if(x >= sx && x < sx + width && newCurrentRow)
3734 if(field) //x >= sx && x < sx + width && newCurrentRow)
3736 if(field == currentField)
3737 editData.Activate();
3739 newCurrentRow.Edit(currentField);*/
3741 else if(style.noDragging && newCurrentRow)
3742 NotifyReclick(master, this, newCurrentRow, mods);
3744 else if(style.noDragging && newCurrentRow)
3745 NotifyReclick(master, this, newCurrentRow, mods);
3752 if(result && style.alwaysEdit && currentRow)
3756 DataField field = null;
3761 if(style.collapse && !style.treeBranch)
3764 for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3766 indent += (style.treeBranch) ? 20 : 15;
3769 for(field = fields.first; field; field = field.next)
3771 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3772 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3774 if(!field.prev) width -= indent;
3775 if(x >= sx && x < sx + width)
3777 f = currentField = field;
3784 // Moved NotifySelect after setting currentField for the NotifySelect implementation to be aware of which field is now selected (e.g. WatchesView)
3785 result = NotifySelect(master, this, currentRow, mods);
3786 if(result && style.alwaysEdit && currentRow)
3788 // In case the user specifically clicked on a field (f is set), override any change to currentField that NotifySelect could have done
3789 currentRow.Edit(f ? f : currentField);
3791 // If the user clicked exactly on the edited field,
3793 if(editData && editData.visible && newCurrentRow)
3797 editData.Activate();
3799 else if(style.noDragging && newCurrentRow)
3800 NotifyReclick(master, this, newCurrentRow, mods);
3803 else if(style.noDragging && newCurrentRow)
3804 NotifyReclick(master, this, newCurrentRow, mods);
3808 For drop box to capture...
3811 if(x < 0 || y < 0 || x >= clientSize.w || y >= clientSize.h)
3814 master.parent.Activate();
3823 if(!style.noDragging)
3828 if(x >= 0 && y >= 0 && x < clientSize.w && y < clientSize.h)
3835 OnLeftButtonUp(x, y, mods);
3840 bool OnLeftButtonDown(int x, int y, Modifiers mods)
3842 return OnButtonDown(x,y, mods, false);
3845 bool OnLeftButtonUp(int x, int y, Modifiers mods)
3847 if(resizingField && style.alwaysEdit)
3849 Window::FreeMouseRange();
3851 resizingField = null;
3854 if(dragRow || editRow)
3856 DataRow row, switchRow = rows.last;
3857 int rowY = (style.header) ? rowHeight : 0;
3858 while(switchRow.lastRow) switchRow = switchRow.lastRow;
3859 for(row = firstRowShown; row; row = row.GetNextRow())
3868 if(editRow == switchRow && y >= 0)
3873 for(field = fields.first; field; field = field.next)
3875 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3876 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3879 if(fieldX > x + scroll.x)
3883 if(field && field.editable)
3885 // true: destroy edit box
3886 HideEditBox(true, true, false);
3887 PopupEditBox(field, false);
3889 else if(!style.noDragging)
3890 NotifyReclick(master, this, currentRow, mods);
3892 else if(style.moveRows && switchRow)
3894 if(dragRow == switchRow && movedRow == false)
3896 DataRow row = dragRow;
3900 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3901 selRow.selectedFlag = unselected;
3905 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3907 if(selRow != clickedRow)
3909 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3910 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3916 if(row.selectedFlag)
3917 row.selectedFlag = tempUnselected;
3918 else row.selectedFlag = tempSelected;
3921 row.selectedFlag = tempSelected;
3926 if(style.multiSelect)
3928 if(!switchRow.selectedFlag)
3930 bool foundSwitch = false;
3933 DataRow afterRow = switchRow.prev;
3934 for(row = rows.first; row; row = next)
3936 next = row.GetNextRow();
3937 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
3939 if(!foundSwitch && !after)
3942 afterRow = switchRow;
3944 if(!after || !(row.selectedFlag == selected || row.selectedFlag == tempSelected) ||
3951 else if(row == switchRow)
3958 for(row = rows.first; row; row = row.GetNextRow())
3960 if(row == switchRow || row == dragRow)
3964 // Switch row first: move before
3965 if(row == switchRow)
3967 DataRow actualMoveRow;
3969 if(!switchRow.prev && switchRow.parent == dragRow.parent)
3970 actualMoveRow = null;
3973 actualMoveRow = switchRow.prev ? switchRow.prev : switchRow;
3974 while(actualMoveRow && actualMoveRow.parent != dragRow.parent && actualMoveRow.parent)
3975 actualMoveRow = actualMoveRow.parent;
3978 if(!actualMoveRow || (actualMoveRow && actualMoveRow.parent == dragRow.parent))
3979 if(NotifyMove(master, this, actualMoveRow, mods))
3981 dragRow.Move(actualMoveRow);
3982 NotifyMoved(master, this, actualMoveRow, mods);
3985 // Dragged row first: move after
3988 DataRow actualMoveRow = switchRow;
3989 DataRow nextRow = switchRow.GetNextRow();
3991 while(nextRow && nextRow.parent != dragRow.parent)
3992 nextRow = nextRow.parent ? nextRow.parent.next : null;
3994 actualMoveRow = nextRow.prev;
3997 actualMoveRow = dragRow.parent ? dragRow.parent.subRows.last : rows.last;
3999 if(!actualMoveRow || (actualMoveRow != dragRow && actualMoveRow.parent == dragRow.parent))
4000 if(NotifyMove(master, this, actualMoveRow, mods))
4002 dragRow.Move(actualMoveRow);
4003 NotifyMoved(master, this, actualMoveRow, mods);
4019 if(dragging || style.freeSelect)
4023 rolledOver = dragging = false;
4025 if(x >= 0 && y >= 0 && x < clientSize.w && y < clientSize.h && currentRow && style.freeSelect)
4029 result = NotifySelect(master, this, currentRow, mods);
4030 if(style.alwaysEdit)
4031 currentRow.Edit(currentField);
4035 // if(!(style.freeSelect))
4041 bool OnLeftDoubleClick(int x, int y, Modifiers mods)
4043 int rowStart = -scroll.x;
4045 int rowY = (style.header) ? rowHeight : 0;
4048 OnLeftButtonUp(x,y,mods);
4049 if(style.alwaysEdit)
4051 if(!(style.collapse) || x > 15)
4052 if(editData && editData.visible)
4054 editData.Activate();
4055 NotifyDoubleClick(master, this, x, y, mods);
4059 for(row = firstRowShown; row; row = row.GetNextRow())
4062 if(rowY > y || (style.multiSelect && !row.GetNextRow()))
4064 if(style.treeBranch)
4067 for(parent = (style.rootCollapse) ? row.parent : (row.parent ? row.parent.parent : null); parent; parent = parent.parent)
4076 if((row && style.collapse && (x >= rowStart && x <= rowStart + 18 + plusIndent)) ||
4077 NotifyDoubleClick(master, this, x, y, mods))
4081 if(row && row.subRows.first)
4083 row.collapsed = !row.collapsed;
4087 // We need to return true here so that OnLeftButtonDown can popup the DataBox Editors
4093 bool OnRightButtonDown(int x, int y, Modifiers mods)
4095 return OnButtonDown(x,y, mods, true);
4098 bool OnRightButtonUp(int x, int y, Modifiers mods)
4100 OnLeftButtonUp(x,y,mods);
4101 return NotifyRightClick(master, this, x, y, mods);
4104 bool GoToLetter(unichar ch, bool keyHit)
4106 bool result = false;
4108 bool checkNextField = true;
4109 int len = keyHit ? 0 : strlen(typedString);
4111 typedString = renew typedString char[len + 2];
4112 typedString[len++] = (char)tolower(ch); // TODO: FIX UNICODE
4113 typedString[len] = '\0';
4115 for(field = fields.first; field; field = field.next)
4117 DataRow startRow = currentRow ? currentRow : rows.first;
4119 if(startRow && field.dataType && field.dataType._vTbl[__ecereVMethodID_class_OnGetString] && ch)
4122 bool looped = false;
4123 if(len == 1 && currentRow)
4124 startRow = (next = startRow.GetNextRow(), (next ? next : rows.first));
4126 for(row = startRow; row != startRow || !looped; next = row.GetNextRow(), row = next ? next : rows.first)
4128 void * data = row.GetData(field);
4129 char tempString[1024] = "";
4130 bool needClass = false;
4131 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;
4133 if(string && string[0])
4134 checkNextField = false;
4135 if(string && string[0] && !strnicmp(string, typedString, len))
4137 if(style.multiSelect)
4142 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4143 selRow.selectedFlag = unselected;
4144 row.selectedFlag = selected;
4146 SetCurrentRow(row, true);
4153 if(typingTimeOut && !keyHit)
4154 typingTimer.Start();
4155 if(!result || !typingTimeOut || keyHit)
4156 typedString[len-1] = '\0';
4158 if(!checkNextField || result) break;
4163 bool OnKeyDown(Key key, unichar ch)
4167 if(key == enter || key == keyPadEnter)
4169 if(editData && editData.visible && editData.active)
4171 HideEditBox(true, false, false);
4175 else if(key == escape)
4177 if(resizingField || movingFields || (editData && editData.visible) || dragRow)
4179 if(editData && editData.visible && style.alwaysEdit && !editData.active)
4181 // false: dont destroy edit box
4182 HideEditBox(false, false, false);
4185 resizingField.width = startWidth;
4186 AdaptToFieldWidth(resizingField, true);
4187 resizingField = null;
4200 movingFields = false;
4201 draggingField = null;
4207 if(!currentField || !currentField.editable)
4208 for(field = fields.first; field; field = field.next)
4212 currentField = field;
4216 if((key == f2 || (style.alwaysEdit && (key == ctrlV || key == ctrlC || key == ctrlX || key == shiftInsert || key == ctrlInsert || key == shiftDel))) &&
4217 currentField && currentField.editable)
4219 PopupEditBox(currentField, false);
4220 if(editData && editData.visible)
4222 if(style.alwaysEdit)
4224 editData.Activate();
4225 if(key == ctrlV || key == ctrlC || key == ctrlX || key == shiftInsert || key == ctrlInsert || key == shiftDel)
4227 editData.OnKeyHit(key, ch);
4231 // For Installer to pop up file dialog
4232 NotifyKeyDown(master, this, currentRow, key, ch);
4238 if(!NotifyKeyDown(master, this, currentRow, key, ch))
4241 // Editable fields...
4244 if(style.alwaysEdit && editData && editData.visible)
4245 return editData.OnKeyDown(key, ch);
4246 return true; // We want to pick up the OnKeyHit to replace contents, but skip GoToLetter
4249 if(ch >=32 && ch != 128 && !key.alt && !key.ctrl && GoToLetter(ch, false))
4251 /*if(inactive && window.state != Hidden)
4252 NotifyHighlight(master, this, currentRow, 0);
4255 NotifySelect(master, this, currentRow, 0);
4262 bool OnKeyHit(Key key, unichar ch)
4264 if(!ch && !key.alt && !key.ctrl)
4266 key.code = (SmartKey)key.code;
4268 if(ch >= 32 && !key.alt && !key.ctrl && ch != 128)
4271 if(!currentField || !currentField.editable)
4272 for(field = fields.first; field; field = field.next)
4276 currentField = field;
4280 if(currentField && currentField.editable)
4282 if((!editData || !editData.visible) || !editData.active)
4284 PopupEditBox(currentField, false);
4285 if(editData && editData.visible)
4287 editData.Activate();
4288 editData.OnKeyHit(key, ch);
4295 if(editData && editData.visible && ch && !key.alt && !key.ctrl && editData.active && (key.code != tab || (editData._class == class(EditBox) && ((EditBox)editData).tabKey)))
4298 if(!key.alt && (style.multiSelect || !key.ctrl))
4303 if(style.alwaysEdit)
4308 for(field = currentField.prev; field; field = field.prev)
4312 currentField = field;
4313 HideEditBox(true, true, false);
4314 PopupEditBox(currentField, false);
4320 if(style.collapse && currentRow /*&& !currentField*/) // THIS PREVENTED COLLAPSING THE PROPERTY SHEET
4322 if(currentRow.subRows.first && !currentRow.collapsed)
4324 currentRow.collapsed = true;
4326 else if(currentRow.parent)
4327 SetCurrentRow(currentRow.parent, true);
4332 if(style.collapse && currentRow && currentRow.subRows.first)
4334 if(currentRow.collapsed)
4335 currentRow.collapsed = false;
4337 SetCurrentRow(currentRow.subRows.first, true);
4340 else if(style.alwaysEdit)
4345 for(field = currentField.next; field; field = field.next)
4349 currentField = field;
4350 HideEditBox(true, true, false);
4351 PopupEditBox(currentField, false);
4359 case pageDown: case pageUp:
4360 case end: case home:
4362 int headerSize = ((style.header) ? rowHeight : 0);
4363 int height = clientSize.h + 1 - headerSize;
4366 // true: destroy edit box
4367 // !!! TESTING true HERE !!!
4368 HideEditBox(true, true, false);
4369 // HideEditBox(false, true, false);
4371 oldRow = currentRow;
4373 SNAPDOWN(height, rowHeight);
4374 if((!currentRow || key.code == home) && key.code != end)
4376 currentRow = rows.first;
4384 if(!(style.multiSelect) && currentRow && !currentRow.selectedFlag)
4387 next = currentRow.GetNextRow();
4394 if(!(style.multiSelect) && currentRow && !currentRow.selectedFlag)
4397 next = currentRow.GetPrevRow();
4405 currentRow = lastRow.GetLastRow();
4411 currentRow && (next = currentRow.GetPrevRow()) && c < height / rowHeight;
4412 c++, currentRow = next);
4419 currentRow && (next = currentRow.GetNextRow()) && c < height / rowHeight;
4420 c++, currentRow = next);
4425 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
4426 SetScrollPosition(scroll.x, currentRow.index * rowHeight - height + rowHeight);
4427 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
4428 SetScrollPosition(scroll.x, currentRow ? currentRow.index * rowHeight : 0);
4430 if(style.multiSelect)
4434 if(!(key.shift) && (key.ctrl))
4437 for(row = rows.first; row; row = row.GetNextRow())
4439 if(row.selectedFlag == tempSelected)
4440 row.selectedFlag = selected;
4441 else if(row.selectedFlag == tempUnselected)
4442 row.selectedFlag = unselected;
4448 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4449 selRow.selectedFlag = unselected;
4453 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4455 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
4456 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
4462 if(currentRow.index >= clickedRow.index)
4464 for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
4468 if(selRow.selectedFlag) selRow.selectedFlag = tempUnselected; else selRow.selectedFlag = tempSelected;
4471 selRow.selectedFlag = selected;
4472 if(selRow == currentRow)
4478 for(selRow = currentRow; selRow; selRow = selRow.GetNextRow())
4482 if(selRow.selectedFlag) selRow.selectedFlag = tempUnselected; else selRow.selectedFlag = tempSelected;
4485 selRow.selectedFlag = selected;
4486 if(selRow == clickedRow)
4493 if(!(key.ctrl) && currentRow)
4495 currentRow.selectedFlag = selected;
4498 clickedRow = currentRow;
4503 if(oldRow) oldRow.selectedFlag = unselected;
4504 if(currentRow) currentRow.selectedFlag = selected;
4509 if(style.freeSelect)
4510 NotifyHighlight(master, this, currentRow, 0);
4512 NotifySelect(master, this, currentRow, 0);
4514 if(style.alwaysEdit && currentRow)
4515 currentRow.Edit(currentField /*null*/);
4522 if(style.multiSelect && currentRow)
4524 if(currentRow.selectedFlag)
4527 currentRow.selectedFlag = unselected;
4530 currentRow.selectedFlag = selected;
4533 if(style.freeSelect)
4534 NotifyHighlight(master, this, currentRow, 0);
4536 NotifySelect(master, this, currentRow, 0);
4543 if(!NotifyKeyHit(master, this, currentRow, key, ch))
4546 if(ch >=32 && ch != 128 && !key.alt && !key.ctrl && GoToLetter(ch, true))
4548 /*if(inactive && window.state != Hidden)
4549 return NotifyHighlight(master, this, currentRow, 0);
4552 return NotifySelect(master, this, currentRow, 0);
4559 void OnHScroll(ScrollBarAction action, int position, Key key)
4564 void OnVScroll(ScrollBarAction action, int position, Key key)
4569 for(firstRowShown = rows.first; firstRowShown; firstRowShown = next)
4571 next = firstRowShown.GetNextRow();
4572 if(y >= position || !next) break;
4582 DataRow firstRowShown;
4586 DataField sortField;
4590 public double typingTimeOut;
4603 if(guiApp.GetKeyState(shift)) mods.shift = true;
4604 if(guiApp.GetKeyState(alt)) mods.alt = true;
4605 if(guiApp.GetKeyState(control)) mods.ctrl = true;
4606 OnMouseMove(MAXINT, MAXINT, mods);
4614 delay = 0.5; // typingTimeOut
4619 typedString[0] = '\0';
4621 // The next line was commented... Why? When commented typing words stops working ( only first character jumps )
4627 bool dragging, rolledOver;
4636 // For editing fields
4638 DataField currentField;
4641 // For moving fields
4642 DataField draggingField, dropField;
4645 // For resizing fields
4646 DataField resizingField;
4647 int resizeX, oldX, startWidth;
4650 FontResource boldFont;
4653 // Only used for OnMouseMove so far, for avoiding problems with consequential mouse moves
4654 bool insideNotifySelect;
4655 ColorAlpha selectionColor, selectionText, stippleColor;
4656 stippleColor = 0xFFFFFF80;