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 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)
156 listBox.fields.Move(this, after);
159 listBox.OnResize(listBox.clientSize.w, listBox.clientSize.h);
160 listBox.Update(null);
166 if(listBox && dataType)
168 Display display = listBox.display;
169 Font boldFont = listBox.boldFont.font;
170 Font font = listBox.fontObject;
174 display.FontExtent(boldFont, header, strlen(header), &width, null);
175 width += EXTRA_SPACE;
176 for(row = listBox.firstRow; row; row = row.GetNextRow())
180 for(i = 0, cell = row.cells.first; i != index; i++, cell = cell.next);
181 if(cell && cell.isSet && dataType)
183 static char tempString[4096];
186 if(dataType.type == normalClass || dataType.type == noHeadClass)
187 string = ((char *(*)(void *, void *, char *, void *, bool *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, cell.data[0], tempString, userData, null);
189 string = ((char *(*)(void *, void *, char *, void *, bool *))(void *)dataType._vTbl[__ecereVMethodID_class_OnGetString])(dataType, cell.data, tempString, userData, null);
191 display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, null);
193 display.FontExtent(row.header ? boldFont : font, "", 0, &tw, null);
194 if(tw > width) width = tw;
198 property::width = width;
205 // property::dataType = "String";
206 property::dataType = "char *";
218 headButton.Destroy(0);
223 listBox.fields.Remove(this);
224 for(field = listBox.fields.first; field; field = field.next)
226 if(field.index >= index)
229 if(listBox.currentField == this)
230 listBox.currentField = null;
232 listBox.OnResize(listBox.clientSize.w, listBox.clientSize.h);
237 DataField prev, next;
261 property int64 tag { set { tag = value; } get { return tag; } };
262 property DataRow previous { get { return prev; } };
263 property DataRow next { get { return next; } };
264 property int index { get { return (this && (!parent || parent.IsExpanded())) ? index : -1; } };
265 property char * string
267 set { SetData(listBox.fields.first, value); }
268 get { return GetData(listBox.fields.first); }
270 property bool isHeader { set { header = value; } get { return this ? header : false; } };
271 property BitmapResource icon { set { icon = value; } get { return icon; } };
272 property bool collapsed
276 if(collapsed != value)
279 if(parent.IsExpanded())
286 for(search = subRows.first; search; search = search.next)
287 search.selectedFlag = 0;
289 if(listBox.clickedRow && !listBox.clickedRow.parent.IsExpanded())
291 listBox.clickedRow = GetNextRow();
292 if(!listBox.clickedRow)
293 listBox.clickedRow = this;
295 if(listBox.currentRow && !listBox.currentRow.parent.IsExpanded())
297 listBox.SetCurrentRow(this, true);
299 if(listBox.firstRowShown && !listBox.firstRowShown.parent.IsExpanded())
301 listBox.firstRowShown = GetPrevRow();
302 if(!listBox.firstRowShown)
303 listBox.firstRowShown = this;
307 index = this.index+1;
308 for(search = GetNextRow(); search; search = search.GetNextRow())
309 search.index = index++;
310 listBox.rowCount = index;
312 listBox.HideEditBox(false, false, true);
314 listBox.SetScrollArea(
316 (listBox.rowCount * listBox.rowHeight) +
317 ((listBox.style.header) ? listBox.rowHeight : 0) -
318 ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
319 listBox.Update(null);
320 listBox.NotifyCollapse(listBox.master, listBox, this, value);
325 listBox.CheckConsistency();
328 get { return this ? collapsed : false; }
330 property bool selected
336 selectedFlag = value ? selected : unselected;
337 listBox.Update(null);
340 get { return selectedFlag == selected || selectedFlag == tempSelected; }
342 property DataRow parent
346 if(this && (value != this))
349 DataRow after = value ? value.subRows.last : listBox.rows.last;
350 int ixCount = (!collapsed && subRows.count) ? GetLastRow().index - index + 1 : 1;
351 if(parent.IsExpanded())
353 for(search = GetNextRow(); search; search = search.GetNextRow())
354 search.index -= ixCount;
355 listBox.rowCount -= ixCount;
358 listBox.HideEditBox(false, false, true);
361 if(this == listBox.clickedRow)
363 listBox.clickedRow = GetNextRow();
364 if(!listBox.clickedRow)
365 listBox.clickedRow = GetPrevRow();
368 if(this == listBox.currentRow)
370 DataRow newCurrentRow = GetNextRow();
371 if(!listBox.newCurrentRow)
372 listBox.newCurrentRow = GetPrevRow();
373 listBox.SetCurrentRow(newCurrentRow, true);
376 if(this == listBox.firstRowShown)
378 listBox.firstRowShown = GetPrevRow();
379 if(!listBox.firstRowShown)
380 listBox.firstRowShown = GetNextRow();
384 (parent ? parent.subRows : listBox.rows).Remove(this);
387 value.subRows.Insert(after, this);
389 listBox.rows.Insert(after, this);
393 if(value && listBox.style.expandOnAdd)
396 value.skipCheck = true;
398 value.collapsed = false;
400 value.skipCheck = false;
404 if(value.IsExpanded())
408 if(after && after.subRows.first && !after.collapsed)
410 search = after.GetLastRow();
411 index = search.index + 1;
414 index = after ? (after.index + 1) : (index + 1);
416 listBox.rowCount += ixCount;
420 for(search = GetNextRow(); search; search = search.GetNextRow())
424 listBox.SetScrollArea(
426 (listBox.rowCount * listBox.rowHeight) +
427 ((listBox.style.header) ? listBox.rowHeight : 0) -
428 ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
429 if(listBox.style.autoScroll)
430 listBox.SetScrollPosition(0, MAXINT - listBox.rowHeight);
432 // TESTING THIS HERE...
434 listBox.Sort(listBox.sortField, listBox.sortField.sortOrder);
437 int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
438 int height = listBox.clientSize.h + 1 - headerSize;
439 if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
440 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
441 else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
443 int line = listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0;
444 listBox.SetScrollPosition(listBox.scroll.x, line);
447 listBox.OnVScroll(0, listBox.scroll.y, 0);
449 listBox.Update(null);
457 property DataRow lastRow { get { return this ? subRows.last : null; } };
458 property DataRow firstRow { get { return this ? subRows.first : null; } };
460 void Edit(DataField field)
466 if(!field || !field.editable)
468 for(field = listBox.fields.first; field; field = field.next)
469 if(field.editable) break;
471 if(field && field.editable)
473 listBox.SetCurrentRow(this, true);
474 listBox.PopupEditBox(field, false);
480 // NOTE: This does not support reparenting (Use row.parent = first)
481 void Move(DataRow after)
486 if(listBox && prev != after)
490 int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
491 int height = listBox.clientSize.h + 1 - headerSize;
492 int ixCount = (!collapsed && subRows.count) ? GetLastRow().index - index + 1 : 1;
494 if(!after || after.index < index)
496 if(after == listBox.firstRowShown.prev)
497 listBox.firstRowShown = this;
499 // All rows between AFTER (exclusive) and ROW (exclusive) are incremented by one
500 // ROW is equal to AFTER's index + 1
502 for(search = after ? after.next : listBox.rows.first; search && search != this; search = search.GetNextRow())
503 search.index += ixCount;
505 if(after && after.subRows.first && !after.collapsed)
507 search = after.GetLastRow();
508 index = search.index + 1;
511 index = after ? (after.index + 1) : 0;
513 // Fix indices of sub rows
517 for(c = 1, search = GetNextRow(); search && c < ixCount; c++, search = search.GetNextRow())
523 DataRow nextRow = GetNextRow();
524 if(this == listBox.firstRowShown)
525 listBox.firstRowShown = nextRow;
528 // All rows between ROW (exclusive) and AFTER (inclusive) are decremented by one
529 // ROW is equal to AFTER's index
531 for(search = nextRow; search; search = search.GetNextRow())
533 search.index -= ixCount;
534 if(search == after) break;
537 listBox.rows.Move(this, after);
540 listBox.CheckConsistency();
543 listBox.HideEditBox(true, false, true);
546 if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
547 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
548 else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
550 int line = listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0;
551 //SNAPUP(line, listBox.rowHeight);
552 listBox.SetScrollPosition(listBox.scroll.x, line);
555 listBox.OnVScroll(0, listBox.scroll.y, 0);
557 listBox.modifiedDocument = true;
559 listBox.Update(null);
566 any_object GetData(DataField field)
570 ListBoxCell cell = listBox.GetCell(&this, &field);
571 if(cell && cell.isSet && cell.data)
573 if((field.dataType.type == normalClass || field.dataType.type == noHeadClass))
576 return (void *)cell.data; // Cast for MemoryGuard
582 void * SetData(DataField field, any_object newData)
586 ListBoxCell cell = listBox.GetCell(&this, &field);
589 Class dataType = field.dataType;
593 if(dataType.type == normalClass || dataType.type == noHeadClass)
595 if(cell.data[0] && field.freeData)
596 ((void (*)(void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnFree])(dataType, cell.data[0]);
598 if(eClass_IsDerived(dataType, class(char *)) && field.freeData)
599 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCopy])(dataType, cell.data, newData);
601 cell.data[0] = (void *)newData;
605 // Free old data first
606 ((void (*)(void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnFree])(dataType, cell.data);
607 ((void (*)(void *, void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnCopy])(dataType, cell.data, newData);
611 listBox.modifiedDocument = true;
612 listBox.Update(null);
613 if(dataType && (dataType.type == normalClass || dataType.type == noHeadClass))
614 return (void *)cell.data; // Cast for MemoryGuard
622 void UnsetData(DataField field)
626 ListBoxCell cell = listBox.GetCell(&this, &field);
629 Class dataType = field.dataType;
633 if(dataType.type == normalClass || dataType.type == noHeadClass)
635 if(cell.data[0] && field.freeData)
636 ((void (*)(void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnFree])(dataType, cell.data[0]);
641 // Free old data first
642 ((void (*)(void *, void *))(void *)dataType._vTbl[__ecereVMethodID_class_OnFree])(dataType, cell.data);
646 listBox.Update(null);
651 DataRow FindRow(int64 tag)
654 for(row = subRows.first; row; row = row.next)
656 if(!row.noneRow && row.tag == tag)
662 DataRow FindSubRow(int64 tag)
665 for(row = subRows.first; row; row = row.next)
667 if(!row.noneRow && row.tag == tag)
669 if(row.subRows.first)
671 DataRow subRow = row.FindSubRow(tag);
679 DataRow AddRowAfter(DataRow after)
689 subRows.Insert(after, row);
690 row.listBox = listBox;
694 for(c = 0; c<listBox.fields.count; c++)
696 for(field = listBox.fields.first; field; field = field.next)
697 if((int)field.index == c)
701 int size = (field.dataType && field.dataType.typeSize) ?
702 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
703 ListBoxCell cell = (ListBoxCell)new0 byte[size];
705 FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
714 if(after && after.subRows.first && !after.collapsed)
716 for(search = after.subRows.last; !search.collapsed && search.subRows.last; )
717 search = search.subRows.last;
718 row.index = search.index + 1;
721 row.index = after ? (after.index + 1) : (index + 1);
725 for(search = row.GetNextRow(); search; search = search.GetNextRow())
728 listBox.SetScrollArea(
730 (listBox.rowCount * listBox.rowHeight) +
731 ((listBox.style.header) ? listBox.rowHeight : 0) -
732 ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
733 if(listBox.style.autoScroll)
734 listBox.SetScrollPosition(0, MAXINT - listBox.rowHeight);
737 listBox.modifiedDocument = true;
740 listBox.CheckConsistency();
750 return AddRowAfter(subRows.last);
754 DataRow AddStringf(char * format, ...)
759 char string[MAX_F_STRING];
761 va_start(args, format);
762 vsnprintf(string, sizeof(string), format, args);
763 string[sizeof(string)-1] = 0;
767 row.SetData(null, string);
773 DataRow AddString(char * string)
779 row.SetData(listBox.fields.first, string);
789 subRows.offset = (uint)&((DataRow)0).prev;
794 ListBoxCell cell, next;
799 while((subRow = subRows.first))
801 subRows.Remove(subRow);
805 for(cell = cells.first; cell; cell = next, cellIndex++)
810 for(field = listBox.fields.first; field && field.index != cellIndex; field = field.next);
811 if(field && field.dataType)
813 // TOCHECK: Is this check good? Will need incref/decref sometime?
814 if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
816 if(cell.data[0] && field.freeData)
817 ((void (*)(void *, void *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnFree])(field.dataType, cell.data[0]);
820 ((void (*)(void *, void *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnFree])(field.dataType, cell.data);
830 return !this || (!collapsed && (!parent || parent.IsExpanded()));
833 int Compare(DataRow b, DataField sortField)
836 ListBoxCell cell1, cell2;
838 for(index = 0, cell1 = cells.first, cell2 = b.cells.first;
839 index != sortField.index;
840 index++, cell1 = cell1.next, cell2 = cell2.next);
842 if(!cell1.isSet && !cell2.isSet)
844 else if(!cell1.isSet)
846 else if(!cell2.isSet)
849 if(noneRow && !b.noneRow) return -1;
850 else if(!noneRow && b.noneRow) return 1;
851 else if(noneRow && b.noneRow) return 0;
853 if(sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare])
855 if(sortField.dataType.type == normalClass || sortField.dataType.type == noHeadClass)
857 result = ((int (*)(void *, void *, void *))(void *)sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare])(sortField.dataType,
858 (cell1.isSet && cell1.data) ? cell1.data[0] : null,
859 (cell2.isSet && cell2.data) ? cell2.data[0] : null);
863 result = ((int (*)(void *, void *, void *))(void *)sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare])(sortField.dataType,
864 cell1.isSet ? cell1.data : null,
865 cell2.isSet ? cell2.data : null);
868 return sortField.sortOrder * result;
871 void _SortSubRows(DataField field, int order)
874 for(search = subRows.first; search; search = search.next)
875 search._SortSubRows(field, order);
876 subRows.Sort(Compare, field);
879 public void SortSubRows(bool scrollToCurrent)
881 if(this && listBox && listBox.sortField)
883 _SortSubRows(listBox.sortField, listBox.sortField.sortOrder);
887 int index = this.index;
888 for(search = this; search; search = search.GetNextRow())
889 search.index = index++;
893 int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
894 int height = listBox.clientSize.h + 1 - headerSize;
895 if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
896 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
897 else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
898 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0);
899 listBox.OnVScroll(0, listBox.scroll.y, 0);
904 public DataRow GetPrevRow()
910 for(row = prev; row && !row.collapsed && row.subRows.last; row = row.subRows.last);
917 public DataRow GetNextRow()
921 if(subRows.first && !collapsed)
925 for(row = this; row; row = row.parent)
927 if(row.next) { row = row.next; break; }
933 private DataRow GetLastRow()
936 while(row && !row.collapsed && row.subRows.last)
937 row = row.subRows.last;
944 SelectedFlag selectedFlag;
955 public class ListBox : CommonControl
957 hasVertScroll = true;
958 // background = white;
960 snapVertScroll = true;
962 class_property(icon) = "<:ecere>controls/listBox.png";
966 property bool freeSelect { property_category $"Behavior" set { style.freeSelect = value; } get { return style.freeSelect; } };
967 property DataRow currentRow { property_category $"Private" /*"Behavior"*/ set { SetCurrentRow(value, false); } get { return currentRow; } };
968 property DataField currentField
970 get { return currentField; }
971 // TODO: Document what this does
974 currentField = value;
975 HideEditBox(true, true, false);
976 if(value && value.editable)
977 PopupEditBox(currentField, false);
981 property int rowHeight
983 property_category $"Appearance"
984 isset { return style.heightSet; }
989 style.heightSet = true;
991 SetScrollLineStep(8, value);
995 style.heightSet = false;
1000 get { return rowHeight; }
1002 property Seconds typingTimeout
1004 property_category $"Behavior"
1007 typedString[0] = '\0';
1008 typingTimer.delay = value;
1009 typingTimeOut = value;
1011 get { return typingTimeOut; }
1013 property bool moveRows { property_category $"Behavior" set { style.moveRows = value; } get { return style.moveRows; } };
1014 property bool moveFields { property_category $"Behavior" set { style.moveFields = value; } get { return style.moveFields; } };
1015 property bool resizable { property_category $"Behavior" set { style.resizable = value; } get { return style.resizable; } };
1016 property bool autoScroll { property_category $"Behavior" set { style.autoScroll = value; } get { return style.autoScroll; } };
1017 property bool alwaysHighLight { property_category $"Appearance" set { style.alwaysHL = value; } get { return style.alwaysHL; } };
1018 property bool hasClearHeader { property_category $"Appearance" set { style.clearHeader = value; if(value) property::hasHeader = true; } get { return style.clearHeader; } };
1019 property bool hasHeader
1021 property_category $"Appearance"
1024 if(value && !style.header)
1030 bevel = !guiApp.textMode && !style.clearHeader;
1031 dontScrollVert = true;
1034 NotifyPushed = HeaderPushed;
1035 NotifyClicked = HeaderClicked;
1036 NotifyDoubleClick = HeaderDoubleClicked;
1037 NotifyReleased = HeaderReleased;
1038 NotifyMouseMove = HeaderMouseMove;
1042 endBevel.visible = false;
1044 style.header = value;
1046 get { return style.header; }
1048 property bool multiSelect { property_category $"Behavior" set { style.multiSelect = value; } get { return style.multiSelect; } };
1049 property bool alwaysEdit { property_category $"Behavior" set { style.alwaysEdit = value; } get { return style.alwaysEdit; } };
1050 property bool fullRowSelect { property_category $"Appearance" set { style.fullRowSelect = value; } get { return style.fullRowSelect; } };
1051 property bool collapseControl { property_category $"Appearance" set { style.collapse = value; } get { return style.collapse; } };
1052 property bool treeBranches { property_category $"Appearance" set { style.treeBranch = value; } get { return style.treeBranch; } };
1053 property bool rootCollapseButton { property_category $"Appearance" set { style.rootCollapse = value; } get { return style.rootCollapse; } };
1054 property bool sortable { property_category $"Behavior" set { style.sortable = value; } get { return style.sortable; } };
1055 property bool noDragging { property_category $"Behavior" set { style.noDragging = value; } get { return style.noDragging; } };
1056 property bool fillLastField
1058 property_category $"Behavior"
1061 style.fillLastField = value;
1063 get { return style.fillLastField; }
1065 property int numSelections
1069 int numSelections = 0;
1070 if(this && style.multiSelect)
1073 for(row = rows.first; row; row = row.GetNextRow())
1074 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
1077 return numSelections;
1080 property int currentIndex
1082 get { return currentRow ? currentRow.index : -1; }
1084 property DataRow lastRow { get { return this ? rows.last : null; } };
1085 property DataRow firstRow { get { return this ? rows.first : null; } };
1086 property int rowCount { get { return rowCount; } };
1087 property DataField firstField { get { return this ? fields.first : null; } };
1088 property Color selectionColor { set { selectionColor = value; } get { return selectionColor; } isset { return selectionColor ? true : false; } };
1089 property Color selectionText { set { selectionText = value; } get { return selectionText; } isset { return selectionText ? true : false; } };
1090 property Color stippleColor { set { stippleColor = value; } get { return stippleColor; } };
1091 property bool expandOnAdd { set { style.expandOnAdd = value; } get { return style.expandOnAdd; } };
1094 virtual bool Window::NotifySelect(ListBox listBox, DataRow row, Modifiers mods);
1095 virtual bool Window::NotifyHighlight(ListBox listBox, DataRow row, Modifiers mods);
1096 virtual bool Window::NotifyReclick(ListBox listBox, DataRow row, Modifiers mods);
1097 virtual bool Window::NotifySort(ListBox listBox, DataField field, Modifiers mods);
1098 virtual bool Window::NotifyChanged(ListBox listBox, DataRow row);
1099 virtual bool Window::NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch);
1100 virtual bool Window::NotifyEdited(ListBox listBox, DataRow row);
1101 virtual bool Window::NotifyEditDone(ListBox listBox, DataRow row);
1102 virtual bool Window::NotifyMovedField(ListBox listBox, DataField field, Modifiers mods);
1103 virtual bool Window::NotifyMove(ListBox listBox, DataRow row, Modifiers mods);
1104 virtual bool Window::NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods);
1105 virtual bool Window::NotifyRightClick(ListBox listBox, int x, int y, Modifiers mods);
1106 virtual bool Window::NotifyResized(ListBox listBox, DataField field, Modifiers mods);
1107 virtual bool Window::NotifyCollapse(ListBox listBox, DataRow row, bool collapsed);
1108 virtual bool Window::NotifyKeyHit(ListBox listBox, DataRow row, Key key, unichar ch);
1109 virtual bool Window::NotifyModified(ListBox listBox, DataRow row);
1110 virtual bool Window::NotifyEditing(ListBox listBox, DataRow row);
1113 private void CheckConsistency()
1118 for(r = rows.first; r; r = r.GetNextRow())
1120 if(r.index != index++)
1128 void AddField(DataField addedField)
1133 if(fields.first && ((DataField)fields.first).defaultField)
1135 DataField defaultField = fields.first;
1136 defaultField.Free();
1137 delete defaultField;
1141 addedField = DataField { };
1145 addedField.listBox = this;
1146 fields.Add(addedField);
1148 addedField.sortOrder = 1;
1149 addedField.index = numFields;
1153 addedField.headButton.Destroy(0);
1154 delete addedField.headButton;
1155 addedField.headButton = Button
1160 dontScrollVert = true;
1161 id = (uint64)addedField;
1162 text = addedField.header;
1163 bevel = (!guiApp.textMode && !style.clearHeader);
1165 alignment = addedField.alignment;
1166 NotifyPushed = HeaderPushed;
1167 NotifyClicked = HeaderClicked;
1168 NotifyDoubleClick = HeaderDoubleClicked;
1169 NotifyReleased = HeaderReleased;
1170 NotifyMouseMove = HeaderMouseMove;
1172 incref addedField.headButton;
1173 addedField.headButton.Create();
1176 addedField.headButton.background = Color { 0, 170, 0 };
1182 for(row = rows.first; row; )
1184 int size = (field.dataType && field.dataType.typeSize) ?
1185 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1186 ListBoxCell cell = (ListBoxCell)new0 byte[size];
1187 row.cells.Add(cell);
1188 FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
1191 if(row.subRows.first)
1192 row = row.subRows.first;
1195 for(; row; row = row.parent)
1197 if(row.next) { row = row.next; break; }
1202 OnResize(clientSize.w, clientSize.h);
1211 Clear(); // Ensure data is cleared first
1212 while((field = fields.first))
1217 endBevel.visible = false;
1222 void RemoveField(DataField field)
1228 int index = field.index;
1231 if(sortField == field)
1234 for(row = rows.first; row; )
1239 for(cell = row.cells.first, c = 0; c < index && cell; c++, cell = cell.next);
1240 if(cell && index == c)
1244 // TOCHECK: Is this check good? Will need incref/decref sometime?
1245 if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
1247 if(cell.data[0] && field.freeData)
1248 ((void (*)(void *, void *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnFree])(field.dataType, cell.data[0]);
1251 ((void (*)(void *, void *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnFree])(field.dataType, cell.data);
1254 row.cells.Remove(cell);
1258 if(row.subRows.first)
1259 row = row.subRows.first;
1262 for(; row; row = row.parent)
1264 if(row.next) { row = row.next; break; }
1273 endBevel.visible = false;
1277 DataRow AddRowNone()
1279 DataRow row { noneRow = true };
1288 rows.Insert(null, row);
1291 for(search = row.GetNextRow(); search; search = search.GetNextRow())
1297 firstRowShown = row;
1301 (rowCount * rowHeight) +
1302 ((style.header) ? rowHeight : 0) -
1303 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1304 if(style.autoScroll)
1305 SetScrollPosition(0, MAXINT - rowHeight);
1306 modifiedDocument = true;
1325 // Find very last row
1328 for(lastRow = rows.last; lastRow && !lastRow.collapsed && lastRow.subRows.last; lastRow)
1329 lastRow = lastRow.subRows.last;
1330 row.index = lastRow ? (lastRow.index + 1) : 0;
1338 for(c = 0; c<fields.count; c++)
1340 for(field = fields.first; field; field = field.next)
1341 if((int)field.index == c)
1345 int size = (field.dataType && field.dataType.typeSize) ?
1346 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1347 ListBoxCell cell = (ListBoxCell) new0 byte[size];
1348 row.cells.Add(cell);
1349 FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
1356 firstRowShown = row;
1362 (rowCount * rowHeight) +
1363 ((style.header) ? rowHeight : 0) -
1364 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1365 if(style.autoScroll)
1366 SetScrollPosition(0, MAXINT - rowHeight);
1367 modifiedDocument = true;
1378 DataRow AddRowAfter(DataRow after)
1390 if(after && after.subRows.first && !after.collapsed)
1392 for(search = after.subRows.last; !search.collapsed && search.subRows.last; )
1393 search = search.subRows.last;
1394 row.index = search.index + 1;
1397 row.index = after ? (after.index + 1) : 0;
1398 rows.Insert(after, row);
1401 for(search = row.GetNextRow(); search; search = search.GetNextRow())
1406 for(c = 0; c<fields.count; c++)
1408 for(field = fields.first; field; field = field.next)
1409 if((int)field.index == c)
1413 int size = (field.dataType && field.dataType.typeSize) ?
1414 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1415 ListBoxCell cell = (ListBoxCell) new0 byte[size];
1416 row.cells.Add(cell);
1417 FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
1421 if(!firstRowShown || !after)
1423 firstRowShown = row;
1428 (rowCount * rowHeight) +
1429 ((style.header) ? rowHeight : 0) -
1430 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1431 if(style.autoScroll)
1432 SetScrollPosition(0, MAXINT - rowHeight);
1433 modifiedDocument = true;
1443 DataRow AddStringf(char * format, ...)
1449 char string[MAX_F_STRING];
1452 va_start(args, format);
1453 vsnprintf(string, sizeof(string), format ? format : "", args);
1454 string[sizeof(string)-1] = 0;
1458 row.SetData(fields.first, string);
1464 DataRow AddString(char * string)
1470 row.SetData(fields.first, string);
1476 void SelectRow(DataRow row)
1478 SetCurrentRow(row, true);
1481 void DeleteRow(DataRow row)
1483 if(!row) row = currentRow;
1486 DataRow sub, next, search;
1487 // Trying to move this here (Messed up deleting watches)
1488 //HideEditBox(false, false, true);
1491 for(sub = row.subRows.first; sub; sub = next)
1497 if(row.parent.IsExpanded())
1499 for(search = row.GetNextRow(); search; search = search.GetNextRow())
1504 HideEditBox(false, false, true);
1506 if(row == clickedRow)
1508 clickedRow = row.GetNextRow();
1510 clickedRow = row.GetPrevRow();
1513 if(row == currentRow)
1515 DataRow newCurrentRow = row.GetNextRow();
1517 newCurrentRow = row.GetPrevRow();
1518 SetCurrentRow(newCurrentRow, true);
1521 if(row == firstRowShown)
1523 firstRowShown = row.GetPrevRow();
1525 firstRowShown = row.GetNextRow();
1528 (row.parent ? row.parent.subRows: rows).Remove(row);
1531 //HideEditBox(false, false, true);
1535 (this.rowCount * rowHeight) +
1536 ((style.header) ? rowHeight : 0) -
1537 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1539 modifiedDocument = true;
1548 DataRow FindRow(int64 tag)
1553 for(row = rows.first; row; row = row.next)
1555 if(!row.noneRow && row.tag == tag)
1563 DataRow FindString(char * searchedString)
1566 bool checkNextField = true;
1567 int len = searchedString ? strlen(searchedString) : 0;
1569 for(field = fields.first; field; field = field.next)
1571 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1574 for(row = rows.first; row; row = row.GetNextRow())
1578 void * data = row.GetData(field);
1579 char tempString[1024] = "";
1580 bool needClass = false;
1581 char * string = ((char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, data, tempString, null, &needClass);
1583 if(string && string[0])
1584 checkNextField = false;
1585 if(string && string[0] && !strcmp(string, searchedString))
1590 if(!checkNextField) break;
1595 DataRow FindSubString(char * subString)
1598 bool checkNextField = true;
1599 int len = subString ? strlen(subString) : 0;
1603 for(field = fields.first; field; field = field.next)
1605 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1608 for(row = rows.first; row; row = row.GetNextRow())
1612 void * data = row.GetData(field);
1613 char tempString[1024] = "";
1614 bool needClass = false;
1615 char * string = ((char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, data, tempString, null, &needClass);
1617 if(string && string[0])
1618 checkNextField = false;
1619 if(string && string[0] && !strncmp(string, subString, len))
1624 if(!checkNextField) break;
1630 DataRow FindSubStringi(char * subString)
1633 bool checkNextField = true;
1634 int len = subString ? strlen(subString) : 0;
1635 DataRow result = null;
1636 char * bestResult = null;
1641 for(field = fields.first; field; field = field.next)
1643 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1646 for(row = rows.first; row; row = row.GetNextRow())
1650 void * data = row.GetData(field);
1651 char tempString[1024] = "";
1652 bool needClass = false;
1653 char * string = ((char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, data, tempString, null, &needClass);
1655 if(string && string[0])
1656 checkNextField = false;
1657 if(string && string[0])
1659 int stringLen = strlen(string);
1661 if(!strnicmp(string, subString, Min(len, stringLen)))
1663 if(bestLen < Min(len, stringLen))
1665 if(!bestResult || strcmpi(string, bestResult) < 0)
1667 bestLen = Min(len, stringLen);
1668 bestResult = string;
1676 if(!checkNextField) break;
1682 DataRow FindSubStringAfter(DataRow after, char * subString)
1685 bool checkNextField = true;
1686 int len = subString ? strlen(subString) : 0;
1690 for(field = fields.first; field; field = field.next)
1692 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1695 for(row = after.GetNextRow(); row && row != after; row = row.GetNextRow(), (!row) ? (row = rows.first) : null)
1699 void * data = row.GetData(field);
1700 char tempString[1024] = "";
1701 bool needClass = false;
1702 char * string = ((char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, data, tempString, null, &needClass);
1704 if(string && string[0])
1705 checkNextField = false;
1706 if(string && string[0] && !strncmp(string, subString, len))
1711 if(!checkNextField) break;
1717 DataRow FindSubRow(int64 tag)
1723 for(row = rows.first; row; row = row.next)
1725 if(!row.noneRow && row.tag == tag)
1727 if(!row.noneRow && row.subRows.first)
1729 DataRow subRow = row.FindSubRow(tag);
1743 Window master = this.master;
1745 HideEditBox(false, true, false);
1746 editData.Destroy(0);
1748 firstRowShown = currentRow = null;
1753 if(style.freeSelect)
1754 NotifyHighlight(master, this, currentRow ? currentRow : null, 0);
1756 NotifySelect(master, this, currentRow ? currentRow : null, 0);
1759 if(style.alwaysEdit && currentRow)
1760 currentRow.Edit(currentField);
1767 (this.rowCount * rowHeight) +
1768 ((style.header) ? rowHeight : 0) -
1769 ((rowHeight && !((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1774 void Sort(DataField field, int order)
1779 int headerSize = ((style.header) ? rowHeight : 0);
1780 int height = clientSize.h + 1 - headerSize;
1782 if(!field) field = fields.first;
1784 field.sortOrder = order ? order : 1;
1785 rows.Sort(DataRow::Compare, field);
1787 for(search = rows.first; search; search = search.next)
1788 search._SortSubRows(field, order);
1792 for(search = rows.first; search; search = search.GetNextRow())
1793 search.index = index++;
1796 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
1797 SetScrollPosition(scroll.x, currentRow.index * rowHeight - height + rowHeight);
1798 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
1799 SetScrollPosition(scroll.x, currentRow ? currentRow.index * rowHeight : 0);
1801 OnVScroll(0, scroll.y, 0);
1803 // SetScrollPosition(0, scroll.y);
1808 void StopEditing(bool save)
1810 HideEditBox(save, false, true);
1813 void GetMultiSelection(OldList list)
1816 if(this && style.multiSelect)
1820 for(row = rows.first; row; row = row.GetNextRow())
1822 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
1824 list.Add(OldLink { data = row });
1830 // Convenience Current Row Methods
1831 void * SetData(DataField field, any_object data)
1833 return currentRow.SetData(field, data);
1836 any_object GetData(DataField field)
1838 return (void *)currentRow.GetData(field);
1843 return currentRow ? currentRow.tag : 0;
1849 DataField defaultField { };
1850 rows.offset = (uint)&((DataRow)0).prev;
1851 fields.offset = (uint)&((DataField)0).prev;
1852 style.fullRowSelect = true;
1853 style.fillLastField = true;
1854 style.expandOnAdd = true;
1855 typingTimeOut = 0.5;
1856 rowHeight = 16; // Stuff depending on creation and default property checking
1859 defaultField.defaultField = true;
1861 AddField(defaultField);
1863 typedString = new char[1];
1864 typedString[0] = '\0';
1879 while((field = fields.first))
1881 // fields.Remove(field);
1891 while((row = rows.first))
1898 ListBoxCell GetCell(DataRow * row, DataField * field)
1900 ListBoxCell cell = null;
1901 if(!*row) *row = currentRow;
1904 if(!*field) *field = this ? currentField : null;
1907 for(*field = fields.first; (*field).index != 0; *field = (*field).next);
1912 if(field->listBox == this)
1914 for(index = 0, cell = (*row).cells.first; cell && index != (*field).index; index++, cell = cell.next);
1921 void HideEditBox(bool save, bool alwaysStopEdit, bool repositionOnly)
1923 if(editData && editData.visible)
1925 Class dataType = currentField.dataType;
1927 editData.SaveData();
1929 editData.visible = false;
1930 NotifyEditDone(master, this, currentRow);
1932 // ENSURE DATA BOX IS NOT VISIBLE
1933 editData.visible = false;
1935 if(style.alwaysEdit && !alwaysStopEdit)
1938 int height = rowHeight - (style.alwaysEdit ? 1 : 0);
1939 int y = currentRow.index * rowHeight + (style.header ? rowHeight : 0);
1940 int x = currentField.x;
1941 int width = (!currentField.next && style.fillLastField && (!hasHorzScroll || clientSize.w - currentField.x > currentField.width + EXTRA_SPACE)) ?
1942 clientSize.w - currentField.x : (currentField.width + EXTRA_SPACE);
1944 if(!style.alwaysEdit)
1946 editData.position = { x, y };
1947 editData.size = { width, height };
1951 editData.position = { x, y - editData.clientStart.y };
1952 editData.size = { width, height + editData.clientStart.y * 2 };
1954 editData.visible = true;
1955 if(style.alwaysEdit)
1956 editData.Deactivate();
1958 PopupEditBox(currentField, repositionOnly);
1964 currentField = null;*/
1968 void SetCurrentRow(DataRow row, bool notify)
1970 if(currentRow != row || (currentRow && currentRow.selectedFlag == unselected))
1972 int headerSize = ((style.header) ? rowHeight : 0);
1973 int height = clientSize.h + 1 - headerSize;
1975 // true: destroy edit box
1976 HideEditBox(true, true, false);
1978 if(!(style.multiSelect) && currentRow)
1979 currentRow.selectedFlag = unselected;
1983 if(style.multiSelect)
1987 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
1988 selRow.selectedFlag = unselected;
1990 currentRow.selectedFlag = selected;
1995 currentRow.selectedFlag = selected;
1997 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
1998 SetScrollPosition(scroll.x,
1999 currentRow.index * rowHeight - height + rowHeight);
2000 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
2002 int line = currentRow ? currentRow.index * rowHeight : 0;
2003 //SNAPUP(line, rowHeight);
2004 SetScrollPosition(scroll.x, line);
2009 Window master = this.master;
2012 if(style.freeSelect && visible)
2013 NotifyHighlight(master, this, currentRow ? currentRow : null, 0);
2015 NotifySelect(master, this, currentRow ? currentRow : null, 0);
2016 if(style.alwaysEdit && currentRow)
2017 currentRow.Edit(currentField);
2025 void RepositionFieldEditor()
2027 if(editData && editData.visible)
2029 int height = rowHeight - (style.alwaysEdit ? 1 : 0);
2031 int y = currentRow.index * rowHeight + (style.header ? rowHeight : 0);
2035 if(style.collapse && !(style.treeBranch))
2037 for(field = fields.first; field; field = field.next)
2039 width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2040 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2041 if(field == currentField) break;
2044 if(!style.alwaysEdit)
2046 editData.position = { x, y - editData.clientStart.y };
2047 editData.size = { width, height + editData.clientStart.y * 2 };
2051 editData.position = { x, y };
2052 editData.size = { width, height };
2057 void PopupEditBox(DataField whichField, bool repositionOnly)
2059 if((!editData || !editData.visible || currentField != whichField) && currentRow)
2061 // true: destroy edit box
2062 HideEditBox(true, true, false);
2065 int height = rowHeight - (style.alwaysEdit ? 1 : 0);
2067 int y = currentRow.index * rowHeight + (style.header ? rowHeight : 0);
2069 //void * data = currentRow.GetData(whichField);
2074 if(style.collapse && !(style.treeBranch))
2077 for(field = fields.first; field; field = field.next)
2079 width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2080 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2081 if(field == whichField) break;
2085 currentField = whichField;
2086 cell = GetCell(&row, ¤tField);
2093 background = dataBoxBackground;
2094 foreground = dataBoxForeground;
2096 bool NotifyChanged(DataBox dataBox, bool closingDropDown)
2099 DataField field = null;
2100 ListBoxCell cell = GetCell(&row, &field);
2104 modifiedDocument = true;
2106 NotifyChanged(master, this, currentRow);
2111 bool NotifyModified()
2113 //DataRow row = null;
2114 //DataField field = null;
2115 //ListBoxCell cell = GetCell(&row, &field);
2116 //cell.isSet = true;
2117 modifiedDocument = true;
2119 NotifyModified(master, this, currentRow);
2123 bool OnKeyDown(Key key, unichar ch)
2125 bool result = DataBox::OnKeyDown(key, ch);
2126 if(visible && active) // Added this check here, because we will not use enter/escape otherwise, and lose DataBox's result
2128 if((SmartKey)key == enter || (SmartKey)key == escape)
2137 editData.Destroy(0);
2138 editData.type = whichField.dataType;
2139 editData.fieldData = whichField.userData;
2140 editData.borderStyle = style.alwaysEdit ? 0 : deep;
2141 editData.data = cell ? cell.data : null;
2144 // Might not really need this anymore...
2145 NotifyEditing(master, this, currentRow);
2148 if(!style.alwaysEdit)
2150 editData.position = { x, y - editData.clientStart.y };
2151 editData.size = { width, height + editData.clientStart.y * 2 };
2155 editData.position = { x, y };
2156 editData.size = { width, height };
2160 editData.visible = true;
2162 if(style.alwaysEdit)
2163 editData.Deactivate();
2165 // MOVED THIS HIGHER FOR DATALIST EDITOR
2167 // Might not really need this anymore...
2168 NotifyEdited(master, this, currentRow);
2173 void OnRedraw(Surface surface)
2176 int y = (style.header) ? rowHeight : 0;
2177 bool isActive = active;
2178 Font font = fontObject;
2179 Font boldFont = this.boldFont.font;
2183 if(style.alwaysEdit && style.fullRowSelect)
2186 int y = (style.header) ? rowHeight : 0;
2187 int x = -scroll.x - 1;// + EXTRA_SPACE;// / 2 - 1;
2188 int w = clientSize.w;
2189 int h = clientSize.h;
2193 // Fill out indent column
2194 if(style.collapse && !(style.treeBranch) && (style.header || rows.first))
2197 surface.SetBackground(formColor);
2198 surface.Area(-scroll.x, 0, x, clientSize.h);
2201 surface.SetForeground(formColor);
2202 for(row = firstRowShown; row; row = row.GetNextRow())
2205 surface.HLine(x + 1, w-1, y-1);
2211 for(field = fields.first; field; field = field.next)
2213 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2214 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2215 if(field.prev && y > 0)
2216 surface.VLine(0, y-1, x);
2221 surface.foreground = this.foreground;
2222 surface.TextOpacity(false);
2224 // Draw the tree branches
2225 if(style.treeBranch)
2227 int y = -scroll.y + ((style.header) ? rowHeight : 0);
2228 surface.LineStipple(0x5555);
2229 surface.SetForeground(branchesColor);
2230 for(row = rows.first; row; row = row.GetNextRow() )
2232 int x = -scroll.x + EXTRA_SPACE / 2-1;
2233 int rowStart = -scroll.x;
2238 for(parent = row.parent; parent; parent = parent.parent)
2239 if(!parent.header) indent += 20;
2240 if(style.rootCollapse) indent += 20;
2242 plusIndent = (style.treeBranch) ? (indent - 20 + 4) : indent;
2247 if(row.subRows.first)
2250 int y1 = y + PLUSY + 4;
2254 for(child = row.collapsed ? null : row.subRows.first; child && child != row; )
2257 if(child.subRows.first && !child.collapsed && child != row.subRows.last)
2258 child = child.subRows.first;
2263 for(; child && child != row; child = child.parent)
2273 y2 = y + numRows * rowHeight + PLUSY + 4;
2274 surface.VLine(y1, y2, rowStart + plusIndent + 7 + 20);
2276 surface.HLine(rowStart + plusIndent + 7, rowStart + indent, y + PLUSY + 4);
2279 if(y >= clientSize.h)
2282 // Root Vertical Lines
2283 if(style.rootCollapse && rows.first)
2288 y = -scroll.y + ((style.header) ? rowHeight : 0);
2290 for(child = rows.first; child && child != rows.last; )
2293 if(child.subRows.first && !child.collapsed && child != rows.last)
2294 child = child.subRows.first;
2299 for(; child; child = child.parent)
2309 y2 = y + numRows * rowHeight + PLUSY + 4;
2310 surface.VLine(y1, y2, -scroll.x + 11);
2312 surface.LineStipple(0);
2315 for(row = firstRowShown; row; row = row.GetNextRow() )
2317 int x = -scroll.x + EXTRA_SPACE / 2-1;
2320 Color foreground = this.foreground /*black*/, background = this.background /*white*/;
2321 DataDisplayFlags dataDisplayFlags = 0;
2322 int rowStart = -scroll.x;
2325 Bitmap icon = row.icon ? row.icon.bitmap : null;
2326 int collapseRowStart;
2327 bool lastWasHeader = row.header;
2329 for(parent = row.parent; parent; parent = parent.parent)
2331 if(!parent.header || lastWasHeader)
2333 if(style.treeBranch)
2339 if(style.rootCollapse) indent += 20;
2342 dataDisplayFlags.fullRow = style.fullRowSelect;
2343 dataDisplayFlags.active = isActive;
2344 dataDisplayFlags.header = row.header;
2349 collapseRowStart = rowStart;
2351 if(!(style.treeBranch))
2358 if(style.multiSelect)
2360 dataDisplayFlags.selected = row.selectedFlag == selected || row.selectedFlag == tempSelected;
2361 dataDisplayFlags.current = row == currentRow || (!currentRow && row == firstRowShown);
2365 dataDisplayFlags.selected = row.selectedFlag == selected || row.selectedFlag == tempSelected;
2366 dataDisplayFlags.current = row == currentRow || (!currentRow && row == firstRowShown);
2368 if(row == currentRow)
2370 dataDisplayFlags.current = true;
2371 dataDisplayFlags.selectedFlag = true;
2373 else if(!currentRow && row == firstRowShown)
2375 dataDisplayFlags.current = true;
2379 surface.TextOpacity(true);
2381 background = this.background;
2382 foreground = this.foreground;
2384 // Draw the current row background
2387 Color colors[] = { formColor, azure, mistyRose, linen, floralWhite, lavender, lavenderBlush, lemonChiffon };
2390 while(p = p.parent) level++;
2391 background = colors[(level % (sizeof(colors)/sizeof(colors[0]))];
2392 surface.SetBackground(background);
2393 surface.Area(rowStart, y, clientSize.w, (y + rowHeight) - 1);
2394 foreground = branchesColor;
2396 else if(dataDisplayFlags.selected)
2398 if(dataDisplayFlags.selected && (isActive || style.alwaysHL || (style.alwaysEdit && style.fullRowSelect)))
2400 if(!isActive && style.alwaysEdit)
2401 background = formColor;
2403 background = selectionColor ? selectionColor : SELECTION_COLOR;
2404 if(style.fullRowSelect)
2406 int offset = (style.alwaysEdit) ? 2 : 1;
2407 surface.SetBackground(background);
2408 surface.Area(rowStart, y, clientSize.w, (y + rowHeight) - offset);
2410 if(isActive || !(style.alwaysEdit))
2411 foreground = selectionText ? selectionText : SELECTION_TEXT;
2413 foreground = branchesColor;
2419 surface.Blit(icon, x + (20 - icon.width) /2,y + 2,0,0, icon.width, icon.height);
2425 int width = clientSize.w;
2427 dataDisplayFlags.firstField = true;
2428 clip.left = x - EXTRA_SPACE / 2+1;
2430 clip.right = x + width - EXTRA_SPACE/2 - 0;
2431 clip.bottom = y + rowHeight - 1;
2432 surface.Clip(&clip);
2434 surface.TextFont(font);
2436 surface.SetForeground(foreground);
2437 surface.SetBackground(background);
2439 ((void (*)(void *, 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);
2443 if(!opacity) surface.TextOpacity(false);
2445 for(field = fields.first; field; field = field.next)
2448 int width = ((!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) || row.header) ?
2449 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2451 // Box clip = { x, y+1, x + field.width - EXTRA_SPACE - 1, y + rowHeight - 2 };
2454 //width -= EXTRA_SPACE;
2456 if(!field.prev) width -= indent;
2459 dataDisplayFlags.firstField = field.prev ? false : true;
2461 if(!dataDisplayFlags.firstField && !dataDisplayFlags.fullRow)
2463 background = this.background;
2464 foreground = this.foreground;
2467 if(!isActive && dataDisplayFlags.selected && style.alwaysEdit && field.editable && opacity)
2470 surface.SetBackground(background);
2471 surface.Area(x-3, y, x+width-1, y + rowHeight-2);
2474 clip.left = x - EXTRA_SPACE / 2+1;
2476 clip.right = x + width - EXTRA_SPACE/2 - 0;
2477 clip.bottom = y + rowHeight - 1;
2478 surface.Clip(&clip);
2480 for(index = 0, cell = row.cells.first; cell && index != field.index; index++, cell = cell.next);
2481 // Should always be as many cells in the row as fields in the listbox
2482 if(cell && cell.isSet && field.dataType)
2485 surface.TextFont(boldFont);
2487 surface.TextFont(font);
2489 surface.SetForeground(foreground);
2490 surface.SetBackground(background);
2492 if(field.dataType.type == noHeadClass || field.dataType.type == normalClass)
2493 ((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);
2495 ((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);
2498 if(!isActive && dataDisplayFlags.selected && style.alwaysEdit && field.editable)
2499 background = formColor;
2501 if(!dataDisplayFlags.firstField && !dataDisplayFlags.fullRow)
2503 background = formColor;
2504 foreground = this.background;
2507 x += width;// + EXTRA_SPACE;
2509 if(row.header) break;
2515 int plusIndent = (style.treeBranch) ? (indent - 20 + 4) : indent;
2517 if(row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)))
2519 surface.SetForeground(row.header ? headerCollapseForeground : this.foreground);
2520 surface.Rectangle(collapseRowStart + 3 + plusIndent, y + PLUSY, collapseRowStart + 11 + plusIndent, y + PLUSY + 8);
2522 surface.SetBackground(row.header ? (formColor) : (this.background)); //white
2523 surface.Area(collapseRowStart + 4 + plusIndent, y + PLUSY + 1, collapseRowStart + 10 + plusIndent, y + PLUSY + 7);
2525 surface.HLine(collapseRowStart + 5 + plusIndent, collapseRowStart + 9 + plusIndent, y+PLUSY+4);
2527 surface.VLine(y + PLUSY + 2, y + PLUSY + 6, collapseRowStart + 7 + plusIndent);
2532 // Draw the current row stipple
2533 if(style.fullRowSelect && !(style.alwaysEdit) && (dataDisplayFlags.current) && isActive)
2538 surface.LineStipple(0x5555);
2539 if(dataDisplayFlags.selected)
2540 surface.SetForeground(stippleColor);
2542 surface.SetForeground(this.foreground);
2545 surface.SetForeground(selectionColor ? selectionColor : SELECTION_COLOR);
2546 surface.Rectangle(0, y, clientSize.w-1, (y + rowHeight) - 1);
2547 surface.LineStipple(0);
2551 if(y >= clientSize.h)
2554 if(firstRowShown) surface.Clip(null);
2555 if(this.dragRow && this.dropIndex != -1)
2557 int dropIndex = this.dropIndex;
2560 if(!style.multiSelect && currentRow.index < this.dropIndex)
2562 surface.DrawingChar(223);
2564 y = style.header ? rowHeight : 0;
2565 y += dropIndex * rowHeight - scroll.y;
2567 surface.SetForeground(Color { 85, 85, 255 });
2568 surface.HLine(0, clientSize.w-1, y);
2569 surface.HLine(0, clientSize.w-1, y + 1);
2573 void OnDrawOverChildren(Surface surface)
2575 if(draggingField && this.dropField)
2577 int position = this.dropField.x;
2578 if(draggingField.x < position)
2579 position += this.dropField.width + EXTRA_SPACE;
2581 surface.SetForeground(Color { 85, 85, 255 });
2582 surface.VLine(0, rowHeight - 1, position - scroll.x - 2);
2583 surface.VLine(0, rowHeight - 1, position - scroll.x);
2585 if(sortField && !style.clearHeader && style.header)
2587 DataField field = sortField;
2588 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2589 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2592 surface.TextExtent(field.header, strlen(field.header), &tw, &th);
2593 if(tw < width - EXTRA_SPACE)
2595 bool up = field.sortOrder == 1;
2599 field.x + 2 - scroll.x, 0,
2600 field.x + width + EXTRA_SPACE - 1 - scroll.x, rowHeight
2602 surface.Clip(&clip);
2603 if(field.alignment == left || field.alignment == center)
2605 if(field.alignment == center)
2606 x = field.x + (width + EXTRA_SPACE - tw) / 2 + tw + EXTRA_SPACE + 4;
2608 x = field.x + tw + EXTRA_SPACE + 4;
2610 x = Min(x, field.x + width - 4);
2612 else if(field.alignment == right)
2614 x = field.x + width - tw - 2*EXTRA_SPACE - 4;
2615 x = Max(x, field.x + 2);
2621 // surface.SetForeground((wmenu.selectedFlag == item) ? white : black);
2622 // surface.WriteText(clientSize.w-8, y+(wmenu.rh - 8)/2, "\020", 1);
2628 surface.SetForeground(Color { 128,128,128 } );
2629 surface.DrawLine(x + 3, y, x, y + 5);
2630 surface.PutPixel(x + 1, y + 5);
2631 surface.PutPixel(x + 1, y + 3);
2632 surface.PutPixel(x + 2, y + 1);
2634 surface.SetForeground(white);
2635 surface.DrawLine(x + 4, y, x + 7, y + 5);
2636 surface.PutPixel(x + 6, y + 5);
2637 surface.PutPixel(x + 6, y + 3);
2638 surface.PutPixel(x + 5, y + 1);
2640 surface.DrawLine(x, y + 6, x + 7, y + 6);
2644 surface.SetForeground(Color { 128,128,128 });
2645 surface.DrawLine(x + 3, y+6, x, y+1);
2646 surface.PutPixel(x + 1, y+1);
2647 surface.PutPixel(x + 1, y+3);
2648 surface.PutPixel(x + 2, y+5);
2650 surface.SetForeground(white);
2651 surface.DrawLine(x + 4, y+6, x + 7, y+1);
2652 surface.PutPixel(x + 6, y+1);
2653 surface.PutPixel(x + 6, y+3);
2654 surface.PutPixel(x + 5, y+5);
2656 surface.DrawLine(x, y, x + 7, y);
2665 void OnResize(int w, int h)
2668 bool showEndBevel = false;
2670 if(style.collapse && !style.treeBranch)
2672 for(field = fields.first; field; field = field.next)
2674 int width = field.width + EXTRA_SPACE;
2682 (rowCount * rowHeight) +
2683 ((style.header) ? rowHeight : 0) -
2684 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
2686 for(field = fields.first; field; field = field.next)
2688 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2689 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2690 if(style.header && field.headButton)
2692 showEndBevel = true;
2695 field.headButton.position = { field.x, 0 };
2696 field.headButton.size = { width, rowHeight };
2697 field.headButton.visible = true;
2700 field.headButton.visible = false;
2704 if(!style.fillLastField && showEndBevel && endBevel)
2706 endBevel.position = { x, 0 };
2707 endBevel.size = { clientSize.w + 2 - x, rowHeight };
2708 endBevel.visible = true;
2711 endBevel.visible = false;
2713 if(style.alwaysEdit && editData && editData.visible)
2715 HideEditBox(true, false, true);
2717 else if(editData && editData.visible)
2718 RepositionFieldEditor();
2721 void AdaptToFieldWidth(DataField field, bool doScroll)
2723 OnResize(clientSize.w, clientSize.h);
2725 // Scroll appropriately
2728 if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x &&
2729 field.x >= field.x + field.width + EXTRA_SPACE - clientSize.w)
2731 SetScrollPosition(field.x + field.width + EXTRA_SPACE - clientSize.w, scroll.y);
2733 else if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x ||
2735 SetScrollPosition(field.x, scroll.y);
2740 bool HeaderPushed(Button control, int x, int y, Modifiers mods)
2742 DataField field = (DataField)control.id;
2743 // false: dont destroy edit box
2744 HideEditBox(true, false, true);
2745 if(style.resizable && ((!field && x < RESIZE_BORDER && fields.last) ||
2746 (field && x < RESIZE_BORDER && field.prev) ||
2747 (field && x >= control.clientSize.w - RESIZE_BORDER)))
2750 field = fields.last;
2751 else if(x < RESIZE_BORDER && field.prev)
2754 if(field.fixed) return false;
2755 resizingField = field;
2756 this.resizeX = x + control.position.x;
2757 this.startWidth = field.width;
2758 this.oldX = x - scroll.x;
2763 if(field.fixed) return false;
2764 draggingField = field;
2765 if(style.moveFields)
2766 field.headButton.stayDown = true;
2767 else if(!style.sortable)
2775 bool HeaderMouseMove(Button control, int x, int y, Modifiers mods)
2780 DataField field = resizingField;
2782 x += control.position.x;
2784 // Tweak to prevent shrinking field if we're actually moving right
2785 if(x - scroll.x > this.oldX &&
2786 this.startWidth + x - this.resizeX < field.width)
2788 this.oldX = x - scroll.x;
2791 this.oldX = x - scroll.x;
2793 field.width = this.startWidth + x - this.resizeX;
2794 field.width = Max(field.width, - EXTRA_SPACE);
2796 AdaptToFieldWidth(field, true);
2798 else if(draggingField)
2800 x += control.position.x;
2801 if(style.moveFields)
2803 DataField field = fields.last;
2805 for(field = fields.first; field; field = field.next)
2807 fieldX += ((field.width || style.resizable) ?
2808 field.width : clientSize.w) + EXTRA_SPACE;
2812 if(draggingField == field)
2814 // Reset scroll position
2815 if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x &&
2816 field.x >= field.x + field.width + EXTRA_SPACE - clientSize.w)
2819 field.x + field.width + EXTRA_SPACE - clientSize.w,
2822 else if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x ||
2824 SetScrollPosition(field.x, scroll.y);
2827 if(this.dropField != field)
2829 this.dropField = field;
2832 int position = field.x;
2834 if(draggingField.x < position)
2836 position += field.width + EXTRA_SPACE - clientSize.w;
2837 if(position > scroll.x)
2838 SetScrollPosition(position, scroll.y);
2843 if(position < scroll.x)
2844 SetScrollPosition(position, scroll.y);
2847 this.movingFields = true;
2853 else if(style.resizable)
2855 DataField field = (DataField)control.id;
2858 if(x < RESIZE_BORDER && field.prev)
2860 if(!field.prev.fixed)
2861 control.cursor = guiApp.GetCursor(sizeWE);
2863 else if(x >= control.clientSize.w - RESIZE_BORDER)
2864 control.cursor = guiApp.GetCursor(sizeWE);
2866 control.cursor = null;
2870 if(x < RESIZE_BORDER && fields.last)
2871 control.cursor = guiApp.GetCursor(sizeWE);
2873 control.cursor = null;
2879 bool HeaderReleased(Button control, int x, int y, Modifiers mods)
2883 NotifyResized(master, this, resizingField, mods);
2884 resizingField = null;
2891 if(style.moveFields)
2896 DataField switchField = fields.last;
2900 x += draggingField.x;
2901 for(field = fields.first; field; field = field.next)
2903 fieldX += ((field.width || style.resizable) ?
2904 field.width : clientSize.w) + EXTRA_SPACE;
2907 switchField = field;
2911 if(switchField && draggingField != switchField && this.dropField)
2913 for(field = fields.first; field; field = field.next)
2915 if(field == switchField || field == draggingField)
2919 // Switch field first: move before
2920 if(field == switchField)
2921 draggingField.Move(switchField.prev);
2922 // Dragged field first: move after
2924 draggingField.Move(switchField);
2926 NotifyMovedField(master, this, draggingField, mods);
2928 draggingField.headButton.stayDown = false;
2933 movingFields = false;
2935 draggingField = null;
2941 bool HeaderClicked(Button control, int x, int y, Modifiers mods)
2943 if(style.header && !this.dropField && style.sortable)
2945 DataField field = (DataField)control.id;
2946 if(sortField == field)
2947 field.sortOrder *= -1;
2952 Sort(sortField, field.sortOrder);
2953 NotifySort(master, this, field, mods);
2959 bool HeaderDoubleClicked(Button control, int x, int y, Modifiers mods)
2963 DataField field = (DataField)control.id;
2966 if(x < RESIZE_BORDER && field.prev)
2968 else if(x >= control.clientSize.w - RESIZE_BORDER);
2974 if(x < RESIZE_BORDER && fields.last)
2975 field = fields.last;
2987 if(style.freeSelect)
2992 this.rolledOver = this.dragging = false;
2999 bool OnLoadGraphics()
3001 display.FontExtent(fontObject, "W", 1, null, &fontH);
3002 if(!style.heightSet)
3004 rowHeight = Max(fontH + 2, 16) + (style.alwaysEdit ? 1 : 0);
3005 SetScrollLineStep(8, rowHeight);
3010 void OnApplyGraphics()
3012 SetScrollLineStep(8, rowHeight);
3016 for(field = fields.first; field; field = field.next)
3018 if(field.headButton)
3020 field.headButton.bevel = (!guiApp.textMode && !style.clearHeader);
3022 field.headButton.background = Color { 0, 170, 0 };
3026 OnResize(clientSize.w, clientSize.h);
3029 bool OnResizing(int *w, int *h)
3033 if(!initSize.w && (!anchor.left.type || !anchor.right.type) && !*w)
3038 Font font = fontObject;
3039 Font boldFont = this.boldFont.font;
3040 Display display = this.display;
3042 for(row = rows.first; row; row = row.GetNextRow())
3044 Bitmap icon = row.icon ? row.icon.bitmap : null;
3045 int x = -scroll.x + EXTRA_SPACE / 2-1;
3049 for(parent = row.parent; parent; parent = parent.parent)
3053 if(style.treeBranch)
3059 if(style.rootCollapse) indent += 20;
3061 if(style.collapse && !(style.treeBranch)) x += 15;
3065 // Compute the rows size
3066 for(field = fields.first; field; field = field.next)
3068 if(((style.resizable && (!(style.alwaysEdit) || field.next)) || field.width) && !row.header)
3069 x += field.width - (field.prev ? 0 : indent);
3074 for(index = 0, cell = row.cells.first; index != field.index; index++, cell = cell.next);
3076 // Should always be as many cells in the row as fields in the listbox
3077 if(cell && cell.isSet && field.dataType)
3079 static char tempString[4096];
3082 if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
3083 string = ((char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, cell.data[0], tempString, field.userData, null);
3085 string = ((char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, cell.data, tempString, field.userData, null);
3087 if(!string) string = "";
3088 display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, &th);
3091 display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, &th);
3093 display.FontExtent(row.header ? boldFont : font, "", 0, &tw, &th);
3096 if(row.header) break;
3100 maxWidth = Max(maxWidth, x);
3106 *h = Min(this.maxShown, this.rowCount) * rowHeight;
3111 if(!*w) *w = rowHeight * 5;
3112 if(!*h) *h = rowHeight * 5;
3119 FontResource font = this.font;
3120 FontResource boldFont
3122 faceName = font.faceName, size = font.size, bold = true
3124 AddResource(boldFont);
3125 RemoveResource(this.boldFont);
3126 this.boldFont = boldFont;
3130 SetInitSize(initSize);
3133 bool OnMouseMove(int x, int y, Modifiers mods)
3135 bool isTimer = false;
3136 int realX = x, realY = y;
3138 if(insideNotifySelect) return true;
3140 if(style.alwaysEdit && style.resizable &&
3141 resizingField && !(mods.isSideEffect))
3144 DataField field = resizingField;
3145 field.width = this.startWidth + x - this.resizeX;
3146 field.width = Max(field.width, - EXTRA_SPACE);
3148 AdaptToFieldWidth(field, true);
3152 if(style.alwaysEdit && style.resizable)
3154 int vx = -scroll.x - 1;
3157 if(style.collapse && !(style.treeBranch))
3160 for(field = fields.first; field; field = field.next)
3162 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3163 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3169 cursor = guiApp.GetCursor(sizeWE);
3173 vx += width + EXTRA_SPACE;
3177 if((editData && editData.visible) || (style.alwaysEdit))
3180 if(x == MAXINT && y == MAXINT)
3187 // ADDED THIS CHECK FOR FieldDropBox LEAKS
3188 if(/*!mods.isSideEffect && */(this.rolledOver || !this.dragging))
3190 int rowY = (style.header) ? rowHeight : 0;
3198 ((vertScroll && vertScroll.visible &&
3199 (y < 0 || y >= clientSize.h)) ||
3200 (horzScroll && horzScroll.visible &&
3201 (x < 0 || x >= clientSize.w))))
3206 if(vertScroll && vertScroll.visible &&
3207 (y < 0 || y >= clientSize.h))
3208 vertScroll.Action((y<0)?up:down, 0, 0);
3209 if(horzScroll && horzScroll.visible &&
3210 (x < 0 || x >= clientSize.w))
3211 horzScroll.Action((x<0)?up:down, 0, 0);
3217 // This must be done after the scrolling took place
3218 rowIndex = firstRowShown ? firstRowShown.index : -1;
3220 y = Min(y, clientSize.h-1);
3221 for(row = firstRowShown; row; row = row.GetNextRow(), rowIndex ++)
3230 if(row && currentRow != row)
3232 if(this.dragRow && style.moveRows)
3234 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
3236 else if(style.multiSelect)
3239 for(thisRow = rows.first; thisRow; thisRow = thisRow.GetNextRow())
3240 if((thisRow.selectedFlag == selected || thisRow.selectedFlag == tempSelected) ||
3246 if(this.dropIndex != rowIndex)
3248 this.dropIndex = rowIndex;
3249 this.editRow = null;
3251 this.movedRow = true;
3254 else if((style.freeSelect || this.dragging) && ((realX>= 0 && realY >= 0 && realX< clientSize.w && realY < clientSize.h) || this.rolledOver))
3256 if(!(style.multiSelect))
3258 if(currentRow)currentRow.selectedFlag = unselected;
3259 if(row)row.selectedFlag = selected;
3263 if(style.multiSelect)
3267 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3269 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3270 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3273 if(rowIndex >= clickedRow.index)
3275 for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
3277 selRow.selectedFlag = (selRow.selectedFlag == selected) ? tempUnselected : tempSelected;
3284 for(selRow = row; selRow; selRow = selRow.GetNextRow())
3286 selRow.selectedFlag = (selRow.selectedFlag == selected) ? tempUnselected : tempSelected;
3287 if(selRow == clickedRow)
3293 if(style.freeSelect)
3294 NotifyHighlight(master, this, currentRow, mods);
3297 insideNotifySelect = true;
3298 NotifySelect(master, this, currentRow, mods);
3299 insideNotifySelect = false;
3302 if(style.alwaysEdit && currentRow)
3303 currentRow.Edit(currentField);
3310 bool OnMouseOver(int x, int y, Modifiers mods)
3313 this.rolledOver = true;
3317 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
3319 // TOCHECK: WAS THIS MISSING ? CHECK FOR SLOWDOWN
3320 if(!active) Update(null);
3322 if(!active && (!swap || !swap.isModal))
3324 // true: destroy edit box
3325 HideEditBox(true, true, false);
3327 else if(!swap || !swap.isModal)
3329 // Bring back edit box
3330 if(currentRow && style.alwaysEdit)
3332 currentRow.Edit(currentField ? currentField : null);
3336 return true; //NotifyActivate(master, this, active, swap, 0);
3340 bool OnButtonDown(int x, int y, Modifiers mods, bool right)
3343 // Check to see if we're dragging the vertical divider
3344 if(style.alwaysEdit && style.resizable && !right)
3346 int vx = -scroll.x - 1;// + EXTRA_SPACE;// / 2 - 1;
3349 if(style.collapse && !(style.treeBranch))
3352 for(field = fields.first; field; field = field.next)
3354 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3355 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3361 resizingField = field.prev;
3363 this.startWidth = resizingField.width;
3365 SetMouseRangeToClient();
3369 vx += width + EXTRA_SPACE;
3373 if(!(style.freeSelect))
3375 int rowY = (style.header) ? rowHeight : 0;
3377 int rowIndex = firstRowShown ? firstRowShown.index : -1;
3378 DataRow previousRow = currentRow;
3379 DataRow newCurrentRow = null;
3380 DataField newCurrentField = null;
3381 bool moveMultiple = false;
3382 int numSelected = 0;
3383 int rowStart = -scroll.x;
3385 if(style.multiSelect)
3392 for(row = rows.first; row; row = row.GetNextRow())
3394 if(row.selectedFlag == tempSelected)
3395 row.selectedFlag = selected;
3396 else if(row.selectedFlag == tempUnselected)
3397 row.selectedFlag = unselected;
3398 if(row.selectedFlag == selected)
3405 for(row = firstRowShown; row; row = row.GetNextRow(), rowIndex ++)
3408 if(rowY > y || (style.multiSelect && !row.GetNextRow()))
3411 if(style.treeBranch)
3414 for(parent = (style.rootCollapse) ? row.parent : (row.parent ? row.parent.parent : null); parent; parent = parent.parent)
3420 /* THIS WAS TOO STRICT:
3421 if(style.collapse && row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)) &&
3422 (x >= rowStart + 3 + plusIndent && y >= rowY - rowHeight + PLUSY && x <= rowStart + 11 + plusIndent && y <= rowY - rowHeight + PLUSY + 8))
3424 if(style.collapse &&
3425 (x >= rowStart && y >= rowY - rowHeight && x <= rowStart + 18 + plusIndent && y <= rowY + rowHeight-1))
3427 if(row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)) && x >= plusIndent)
3428 row.collapsed = !row.collapsed;
3435 newCurrentRow = row;
3437 if(style.multiSelect)
3439 // Deselect everything if user didn't clicked on a row
3443 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3444 selRow.selectedFlag = unselected;
3446 //this.clickedRowIndex = rowIndex;
3448 else if(style.moveRows && !(mods.shift) &&
3449 (row.selectedFlag == selected || row.selectedFlag == tempSelected) &&
3450 !right && !(mods.isActivate))
3451 moveMultiple = true;
3457 if(row.selectedFlag == tempUnselected || row.selectedFlag == unselected)
3459 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3460 selRow.selectedFlag = unselected;
3461 row.selectedFlag = selected;
3464 //this.clickedRowIndex = rowIndex;
3470 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3471 selRow.selectedFlag = unselected;
3475 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3477 if(selRow != clickedRow)
3479 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3480 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3487 if(rowIndex >= clickedRow.index)
3489 for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
3493 if(selRow != clickedRow)
3495 if(selRow.selectedFlag)
3496 selRow.selectedFlag = tempUnselected;
3498 selRow.selectedFlag = tempSelected;
3502 selRow.selectedFlag = selected;
3509 for(selRow = row; selRow; selRow = selRow.GetNextRow())
3513 if(selRow != clickedRow)
3515 if(selRow.selectedFlag)
3516 selRow.selectedFlag = tempUnselected;
3518 selRow.selectedFlag = tempSelected;
3522 selRow.selectedFlag = selected;
3523 if(selRow == clickedRow)
3532 if(row.selectedFlag)
3533 row.selectedFlag = tempUnselected;
3534 else row.selectedFlag = tempSelected;
3537 row.selectedFlag = tempSelected;
3539 //this.clickedRowIndex = rowIndex;
3549 // true: destroy edit box
3552 incref newCurrentRow;
3555 if(currentRow != newCurrentRow)
3556 HideEditBox(true, true, false);
3560 if(newCurrentRow._refCount <= 1)
3561 delete newCurrentRow;
3563 newCurrentRow._refCount--;
3568 if(!(style.multiSelect))
3570 if(currentRow) currentRow.selectedFlag = unselected;
3571 if(newCurrentRow) newCurrentRow.selectedFlag = selected;
3575 if(currentRow != newCurrentRow)
3578 // true: destroy edit box
3581 //incref newCurrentRow;
3582 incref newCurrentRow;
3585 HideEditBox(true, true, false);
3590 int headerSize = ((style.header) ? rowHeight : 0);
3591 int height = clientSize.h + 1 - headerSize;
3593 /*if(newCurrentRow._refCount <= 1)
3594 delete newCurrentRow;
3597 newCurrentRow._refCount--;
3598 //newCurrentRow._refCount--;
3601 currentRow = newCurrentRow;
3603 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
3604 SetScrollPosition(scroll.x,
3605 currentRow.index * rowHeight - height + rowHeight);
3606 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
3608 int line = currentRow ? currentRow.index * rowHeight : 0;
3609 //SNAPUP(line, rowHeight);
3610 SetScrollPosition(scroll.x, line);
3613 // GO THROUGH SetCurrentRow eventually?
3614 // SetCurrentRow(newCurrentRow, true);
3618 if(style.freeSelect)
3619 NotifyHighlight(master, this, currentRow, mods);
3620 else if((moveMultiple || (!(style.multiSelect) && previousRow == currentRow)) &&
3621 newCurrentRow && !(mods.shift))
3625 if(!(mods.isActivate))
3629 this.dragRow = currentRow;
3630 this.dropIndex = -1;
3631 this.movedRow = false;
3633 if(editData && editData.visible && style.alwaysEdit)
3640 if(style.collapse && !style.treeBranch)
3643 for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3645 indent += (style.treeBranch) ? 20 : 15;
3648 for(field = fields.first; field; field = field.next)
3650 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3651 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3653 if(!field.prev) width -= indent;
3654 if(x >= sx && x < sx + width)
3658 if(field == currentField)
3659 editData.Deactivate();
3662 currentRow.Edit(field);
3663 editData.Activate();
3666 else if(!(mods.ctrl) && numSelected <= 1)
3667 this.editRow = currentRow;
3669 if(style.noDragging && newCurrentRow)
3670 NotifyReclick(master, this, newCurrentRow, mods);
3674 // If the user clicked exactly on the edited field,
3676 if(editData && editData.visible && newCurrentRow)
3678 DataField field, whichField;
3682 if(style.collapse && !(style.treeBranch))
3685 whichField = currentField;
3689 for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3691 indent += (style.treeBranch) ? 20 : 15;
3695 for(field = fields.first; field; field = field.next)
3697 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3698 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3699 if(!field.prev) width -= indent;
3700 if(x >= sx && x < sx + width && newCurrentRow)
3705 if(field) //x >= sx && x < sx + width && newCurrentRow)
3707 if(field == currentField)
3708 editData.Activate();
3710 newCurrentRow.Edit(currentField);*/
3712 else if(style.noDragging && newCurrentRow)
3713 NotifyReclick(master, this, newCurrentRow, mods);
3715 else if(style.noDragging && newCurrentRow)
3716 NotifyReclick(master, this, newCurrentRow, mods);
3723 if(result && style.alwaysEdit && currentRow)
3727 DataField field = null;
3732 if(style.collapse && !style.treeBranch)
3735 for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3737 indent += (style.treeBranch) ? 20 : 15;
3740 for(field = fields.first; field; field = field.next)
3742 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3743 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3745 if(!field.prev) width -= indent;
3746 if(x >= sx && x < sx + width)
3748 f = currentField = field;
3755 // Moved NotifySelect after setting currentField for the NotifySelect implementation to be aware of which field is now selected (e.g. WatchesView)
3756 result = NotifySelect(master, this, currentRow, mods);
3757 if(result && style.alwaysEdit && currentRow)
3759 // In case the user specifically clicked on a field (f is set), override any change to currentField that NotifySelect could have done
3760 currentRow.Edit(f ? f : currentField);
3762 // If the user clicked exactly on the edited field,
3764 if(editData && editData.visible && newCurrentRow)
3768 editData.Activate();
3770 else if(style.noDragging && newCurrentRow)
3771 NotifyReclick(master, this, newCurrentRow, mods);
3774 else if(style.noDragging && newCurrentRow)
3775 NotifyReclick(master, this, newCurrentRow, mods);
3779 For drop box to capture...
3782 if(x < 0 || y < 0 || x >= clientSize.w || y >= clientSize.h)
3785 master.parent.Activate();
3794 if(!style.noDragging)
3796 this.dragging = true;
3799 if(x >= 0 && y >= 0 && x < clientSize.w && y < clientSize.h)
3800 this.rolledOver = true;
3805 this.dragging = false;
3806 OnLeftButtonUp(x, y, mods);
3811 bool OnLeftButtonDown(int x, int y, Modifiers mods)
3813 return OnButtonDown(x,y, mods, false);
3816 bool OnLeftButtonUp(int x, int y, Modifiers mods)
3818 if(resizingField && style.alwaysEdit)
3820 Window::FreeMouseRange();
3822 resizingField = null;
3825 if(dragRow || editRow)
3827 DataRow row, switchRow = rows.last;
3828 int rowY = (style.header) ? rowHeight : 0;
3829 for(row = firstRowShown; row; row = row.GetNextRow())
3838 if(this.editRow == switchRow && y >= 0)
3843 for(field = fields.first; field; field = field.next)
3845 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3846 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3849 if(fieldX > x + scroll.x)
3853 if(field && field.editable)
3855 // true: destroy edit box
3856 HideEditBox(true, true, false);
3857 PopupEditBox(field, false);
3859 else if(!style.noDragging)
3860 NotifyReclick(master, this, currentRow, mods);
3862 else if(style.moveRows && switchRow)
3864 if(this.dragRow == switchRow && this.movedRow == false)
3866 DataRow row = this.dragRow;
3870 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3871 selRow.selectedFlag = unselected;
3875 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3877 if(selRow != clickedRow)
3879 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3880 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3886 if(row.selectedFlag)
3887 row.selectedFlag = tempUnselected;
3888 else row.selectedFlag = tempSelected;
3891 row.selectedFlag = tempSelected;
3896 if(style.multiSelect)
3898 if(!switchRow.selectedFlag)
3900 bool foundSwitch = false;
3903 DataRow afterRow = switchRow.prev;
3904 for(row = rows.first; row; row = next)
3906 next = row.GetNextRow();
3907 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
3909 if(!foundSwitch && !after)
3912 afterRow = switchRow;
3914 if(!after || !(row.selectedFlag == selected || row.selectedFlag == tempSelected) ||
3921 else if(row == switchRow)
3928 for(row = rows.first; row; row = row.GetNextRow())
3930 if(row == switchRow || row == this.dragRow)
3934 // Switch row first: move before
3935 if(row == switchRow)
3937 if(NotifyMove(master, this, switchRow.prev, mods))
3938 dragRow.Move(switchRow.prev);
3940 // Dragged row first: move after
3943 if(NotifyMove(master, this, switchRow, mods))
3944 dragRow.Move(switchRow);
3957 if(this.dragging || style.freeSelect)
3961 this.rolledOver = this.dragging = false;
3963 if(x >= 0 && y >= 0 && x < clientSize.w && y < clientSize.h && currentRow && style.freeSelect)
3967 result = NotifySelect(master, this, currentRow, mods);
3968 if(style.alwaysEdit)
3969 currentRow.Edit(currentField);
3973 // if(!(style.freeSelect))
3979 bool OnLeftDoubleClick(int x, int y, Modifiers mods)
3981 int rowStart = -scroll.x;
3983 int rowY = (style.header) ? rowHeight : 0;
3986 OnLeftButtonUp(x,y,mods);
3987 if(style.alwaysEdit)
3989 if(!(style.collapse) || x > 15)
3990 if(editData && editData.visible)
3992 editData.Activate();
3993 NotifyDoubleClick(master, this, x, y, mods);
3997 for(row = firstRowShown; row; row = row.GetNextRow())
4000 if(rowY > y || (style.multiSelect && !row.GetNextRow()))
4002 if(style.treeBranch)
4005 for(parent = (style.rootCollapse) ? row.parent : (row.parent ? row.parent.parent : null); parent; parent = parent.parent)
4014 if((row && style.collapse && (x >= rowStart && x <= rowStart + 18 + plusIndent)) ||
4015 NotifyDoubleClick(master, this, x, y, mods))
4019 if(row && row.subRows.first)
4021 row.collapsed = !row.collapsed;
4025 // We need to return true here so that OnLeftButtonDown can popup the DataBox Editors
4031 bool OnRightButtonDown(int x, int y, Modifiers mods)
4033 return OnButtonDown(x,y, mods, true);
4036 bool OnRightButtonUp(int x, int y, Modifiers mods)
4038 OnLeftButtonUp(x,y,mods);
4039 return NotifyRightClick(master, this, x, y, mods);
4042 bool GoToLetter(unichar ch, bool keyHit)
4044 bool result = false;
4046 bool checkNextField = true;
4047 int len = keyHit ? 0 : strlen(typedString);
4049 typedString = renew typedString char[len + 2];
4050 typedString[len++] = (char)tolower(ch); // TODO: FIX UNICODE
4051 typedString[len] = '\0';
4053 for(field = fields.first; field; field = field.next)
4055 DataRow startRow = currentRow ? currentRow : rows.first;
4057 if(startRow && field.dataType && field.dataType._vTbl[__ecereVMethodID_class_OnGetString] && ch)
4060 bool looped = false;
4061 if(len == 1 && currentRow)
4062 startRow = (next = startRow.GetNextRow(), (next ? next : rows.first));
4064 for(row = startRow; row != startRow || !looped; next = row.GetNextRow(), row = next ? next : rows.first)
4066 void * data = row.GetData(field);
4067 char tempString[1024] = "";
4068 bool needClass = false;
4069 char * string = data ? ((char *(*)(void *, void *, char *, void *, bool *))(void *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString])(field.dataType, data, tempString, null, &needClass) : null;
4071 if(string && string[0])
4072 checkNextField = false;
4073 if(string && string[0] && !strnicmp(string, typedString, len))
4075 if(style.multiSelect)
4078 bool foundRow = false;
4080 //this.clickedRowIndex = 0;
4082 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4084 if(selRow == row) foundRow = true;
4085 selRow.selectedFlag = unselected;
4086 //if(!foundRow) this.clickedRowIndex++;
4088 row.selectedFlag = selected;
4090 SetCurrentRow(row, true);
4097 if(this.typingTimeOut && !keyHit)
4098 typingTimer.Start();
4099 if(!result || !this.typingTimeOut || keyHit)
4100 typedString[len-1] = '\0';
4102 if(!checkNextField || result) break;
4107 bool OnKeyDown(Key key, unichar ch)
4111 if(key == enter || key == keyPadEnter)
4113 if(editData && editData.visible && editData.active)
4115 HideEditBox(true, false, false);
4119 else if(key == escape)
4121 if(resizingField || this.movingFields || (editData && editData.visible) || this.dragRow)
4123 if(editData && editData.visible && style.alwaysEdit && !editData.active)
4125 // false: dont destroy edit box
4126 HideEditBox(false, false, false);
4129 resizingField.width = this.startWidth;
4130 AdaptToFieldWidth(resizingField, true);
4131 resizingField = null;
4134 this.dragRow = null;
4137 this.dragging = false;
4141 this.movingFields = false;
4142 draggingField = null;
4148 if(!currentField || !currentField.editable)
4149 for(field = fields.first; field; field = field.next)
4153 currentField = field;
4157 if((key == f2 || (style.alwaysEdit && (key == ctrlV || key == ctrlC || key == ctrlX || key == shiftInsert || key == ctrlInsert || key == shiftDel))) &&
4158 currentField && currentField.editable)
4160 PopupEditBox(currentField, false);
4161 if(editData && editData.visible)
4163 if(style.alwaysEdit)
4165 editData.Activate();
4166 if(key == ctrlV || key == ctrlC || key == ctrlX || key == shiftInsert || key == ctrlInsert || key == shiftDel)
4168 editData.OnKeyHit(key, ch);
4172 // For Installer to pop up file dialog
4173 NotifyKeyDown(master, this, currentRow, key, ch);
4179 if(!NotifyKeyDown(master, this, currentRow, key, ch))
4182 // Editable fields...
4185 if(style.alwaysEdit && editData && editData.visible)
4186 return editData.OnKeyDown(key, ch);
4187 return true; // We want to pick up the OnKeyHit to replace contents, but skip GoToLetter
4190 if(ch >=32 && ch != 128 && !key.alt && !key.ctrl && GoToLetter(ch, false))
4192 /*if(inactive && window.state != Hidden)
4193 NotifyHighlight(master, this, currentRow, 0);
4196 NotifySelect(master, this, currentRow, 0);
4203 bool OnKeyHit(Key key, unichar ch)
4205 if(!ch && !key.alt && !key.ctrl)
4207 key.code = (SmartKey)key.code;
4209 if(ch >= 32 && !key.alt && !key.ctrl && ch != 128)
4212 if(!currentField || !currentField.editable)
4213 for(field = fields.first; field; field = field.next)
4217 currentField = field;
4221 if(currentField && currentField.editable)
4223 if((!editData || !editData.visible) || !editData.active)
4225 PopupEditBox(currentField, false);
4226 if(editData && editData.visible)
4228 editData.Activate();
4229 editData.OnKeyHit(key, ch);
4236 if(editData && editData.visible && ch && !key.alt && !key.ctrl && editData.active && (key.code != tab || (editData._class == class(EditBox) && ((EditBox)editData).tabKey)))
4239 if(!key.alt && (style.multiSelect || !key.ctrl))
4244 if(style.alwaysEdit)
4249 for(field = currentField.prev; field; field = field.prev)
4253 currentField = field;
4254 HideEditBox(true, true, false);
4255 PopupEditBox(currentField, false);
4261 if(style.collapse && currentRow /*&& !currentField*/) // THIS PREVENTED COLLAPSING THE PROPERTY SHEET
4263 if(currentRow.subRows.first && !currentRow.collapsed)
4265 currentRow.collapsed = true;
4267 else if(currentRow.parent)
4268 SetCurrentRow(currentRow.parent, true);
4273 if(style.collapse && currentRow && currentRow.subRows.first)
4275 if(currentRow.collapsed)
4276 currentRow.collapsed = false;
4278 SetCurrentRow(currentRow.subRows.first, true);
4281 else if(style.alwaysEdit)
4286 for(field = currentField.next; field; field = field.next)
4290 currentField = field;
4291 HideEditBox(true, true, false);
4292 PopupEditBox(currentField, false);
4300 case pageDown: case pageUp:
4301 case end: case home:
4303 int headerSize = ((style.header) ? rowHeight : 0);
4304 int height = clientSize.h + 1 - headerSize;
4307 // true: destroy edit box
4308 // !!! TESTING true HERE !!!
4309 HideEditBox(true, true, false);
4310 // HideEditBox(false, true, false);
4312 oldRow = currentRow;
4314 SNAPDOWN(height, rowHeight);
4315 if((!currentRow || key.code == home) && key.code != end)
4317 currentRow = rows.first;
4325 if(!(style.multiSelect) && currentRow && !currentRow.selectedFlag)
4328 next = currentRow.GetNextRow();
4335 if(!(style.multiSelect) && currentRow && !currentRow.selectedFlag)
4338 next = currentRow.GetPrevRow();
4346 currentRow = lastRow.GetLastRow();
4352 currentRow && (next = currentRow.GetPrevRow()) && c < height / rowHeight;
4353 c++, currentRow = next);
4360 currentRow && (next = currentRow.GetNextRow()) && c < height / rowHeight;
4361 c++, currentRow = next);
4366 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
4367 SetScrollPosition(scroll.x, currentRow.index * rowHeight - height + rowHeight);
4368 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
4369 SetScrollPosition(scroll.x, currentRow ? currentRow.index * rowHeight : 0);
4371 if(style.multiSelect)
4375 if(!(key.shift) && (key.ctrl))
4378 for(row = rows.first; row; row = row.GetNextRow())
4380 if(row.selectedFlag == tempSelected)
4381 row.selectedFlag = selected;
4382 else if(row.selectedFlag == tempUnselected)
4383 row.selectedFlag = unselected;
4389 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4390 selRow.selectedFlag = unselected;
4394 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4396 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
4397 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
4403 if(currentRow.index >= clickedRow.index)
4405 for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
4409 if(selRow.selectedFlag) selRow.selectedFlag = tempUnselected; else selRow.selectedFlag = tempSelected;
4412 selRow.selectedFlag = selected;
4413 if(selRow == currentRow)
4419 for(selRow = currentRow; selRow; selRow = selRow.GetNextRow())
4423 if(selRow.selectedFlag) selRow.selectedFlag = tempUnselected; else selRow.selectedFlag = tempSelected;
4426 selRow.selectedFlag = selected;
4427 if(selRow == clickedRow)
4434 if(!(key.ctrl) && currentRow)
4436 currentRow.selectedFlag = selected;
4439 clickedRow = currentRow;
4444 if(oldRow) oldRow.selectedFlag = unselected;
4445 if(currentRow) currentRow.selectedFlag = selected;
4450 if(style.freeSelect)
4451 NotifyHighlight(master, this, currentRow, 0);
4453 NotifySelect(master, this, currentRow, 0);
4455 if(style.alwaysEdit && currentRow)
4456 currentRow.Edit(currentField /*null*/);
4463 if(style.multiSelect && currentRow)
4465 if(currentRow.selectedFlag)
4468 currentRow.selectedFlag = unselected;
4471 currentRow.selectedFlag = selected;
4474 if(style.freeSelect)
4475 NotifyHighlight(master, this, currentRow, 0);
4477 NotifySelect(master, this, currentRow, 0);
4484 if(!NotifyKeyHit(master, this, currentRow, key, ch))
4487 if(ch >=32 && ch != 128 && !key.alt && !key.ctrl && GoToLetter(ch, true))
4489 /*if(inactive && window.state != Hidden)
4490 return NotifyHighlight(master, this, currentRow, 0);
4493 return NotifySelect(master, this, currentRow, 0);
4500 void OnHScroll(ScrollBarAction action, int position, Key key)
4505 void OnVScroll(ScrollBarAction action, int position, Key key)
4510 for(firstRowShown = rows.first; firstRowShown; firstRowShown = next)
4512 next = firstRowShown.GetNextRow();
4513 if(y >= position || !next) break;
4523 DataRow firstRowShown;
4527 DataField sortField;
4531 double typingTimeOut;
4544 if(guiApp.GetKeyState(shift)) mods.shift = true;
4545 if(guiApp.GetKeyState(alt)) mods.alt = true;
4546 if(guiApp.GetKeyState(control)) mods.ctrl = true;
4547 OnMouseMove(MAXINT, MAXINT, mods);
4555 delay = 0.5; // typingTimeOut
4560 typedString[0] = '\0';
4562 // The next line was commented... Why? When commented typing words stops working ( only first character jumps )
4568 bool dragging, rolledOver;
4577 // For editing fields
4579 DataField currentField;
4582 // For moving fields
4583 DataField draggingField, dropField;
4586 // For resizing fields
4587 DataField resizingField;
4588 int resizeX, oldX, startWidth;
4591 FontResource boldFont;
4594 // Only used for OnMouseMove so far, for avoiding problems with consequential mouse moves
4595 bool insideNotifySelect;
4596 ColorAlpha selectionColor, selectionText, stippleColor;
4597 stippleColor = 0xFFFFFF80;