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 *)dataType._vTbl[__ecereVMethodID_class_OnGetString](dataType, cell.data[0], tempString, userData, null);
189 string = (char *)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(this))
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)
526 listBox.firstRowShown = nextRow;
527 index = after ? (after.index + 1) : 0;
530 // All rows between ROW (exclusive) and AFTER (inclusive) are decremented by one
531 // ROW is equal to AFTER's index
533 for(search = nextRow; search; search = search.GetNextRow())
535 search.index -= ixCount;
536 if(search == after) break;
539 listBox.rows.Move(this, after);
542 listBox.CheckConsistency();
545 listBox.HideEditBox(true, false, true);
548 if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
549 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
550 else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
552 int line = listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0;
553 //SNAPUP(line, listBox.rowHeight);
554 listBox.SetScrollPosition(listBox.scroll.x, line);
557 listBox.OnVScroll(0, listBox.scroll.y, 0);
559 listBox.modifiedDocument = true;
561 listBox.Update(null);
568 any_object GetData(DataField field)
572 ListBoxCell cell = listBox.GetCell(&this, &field);
573 if(cell && cell.isSet && cell.data)
575 if((field.dataType.type == normalClass || field.dataType.type == noHeadClass))
578 return (void *)cell.data; // Cast for MemoryGuard
584 void * SetData(DataField field, any_object newData)
588 ListBoxCell cell = listBox.GetCell(&this, &field);
591 Class dataType = field.dataType;
595 if(dataType.type == normalClass || dataType.type == noHeadClass)
597 if(cell.data[0] && field.freeData)
598 dataType._vTbl[__ecereVMethodID_class_OnFree](dataType, cell.data[0]);
600 if(eClass_IsDerived(dataType, class(char *)) && field.freeData)
601 dataType._vTbl[__ecereVMethodID_class_OnCopy](dataType, cell.data, newData);
603 cell.data[0] = (void *)newData;
607 // Free old data first
608 dataType._vTbl[__ecereVMethodID_class_OnFree](dataType, cell.data);
609 dataType._vTbl[__ecereVMethodID_class_OnCopy](dataType, cell.data, newData);
613 listBox.modifiedDocument = true;
614 listBox.Update(null);
615 if(dataType && (dataType.type == normalClass || dataType.type == noHeadClass))
616 return (void *)cell.data; // Cast for MemoryGuard
624 void UnsetData(DataField field)
628 ListBoxCell cell = listBox.GetCell(&this, &field);
631 Class dataType = field.dataType;
635 if(dataType.type == normalClass || dataType.type == noHeadClass)
637 if(cell.data[0] && field.freeData)
638 dataType._vTbl[__ecereVMethodID_class_OnFree](dataType, cell.data[0]);
643 // Free old data first
644 dataType._vTbl[__ecereVMethodID_class_OnFree](dataType, cell.data);
648 listBox.Update(null);
653 DataRow FindRow(int64 tag)
656 for(row = subRows.first; row; row = row.next)
658 if(!row.noneRow && row.tag == tag)
664 DataRow FindSubRow(int64 tag)
667 for(row = subRows.first; row; row = row.next)
669 if(!row.noneRow && row.tag == tag)
671 if(row.subRows.first)
673 DataRow subRow = row.FindSubRow(tag);
681 DataRow AddRowAfter(DataRow after)
691 subRows.Insert(after, row);
692 row.listBox = listBox;
696 for(c = 0; c<listBox.fields.count; c++)
698 for(field = listBox.fields.first; field; field = field.next)
699 if((int)field.index == c)
703 int size = (field.dataType && field.dataType.typeSize) ?
704 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
705 ListBoxCell cell = (ListBoxCell)new0 byte[size];
707 FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
716 if(after && after.subRows.first && !after.collapsed)
718 for(search = after.subRows.last; !search.collapsed && search.subRows.last; )
719 search = search.subRows.last;
720 row.index = search.index + 1;
723 row.index = after ? (after.index + 1) : (index + 1);
727 for(search = row.GetNextRow(); search; search = search.GetNextRow())
730 listBox.SetScrollArea(
732 (listBox.rowCount * listBox.rowHeight) +
733 ((listBox.style.header) ? listBox.rowHeight : 0) -
734 ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
735 if(listBox.style.autoScroll)
736 listBox.SetScrollPosition(0, MAXINT - listBox.rowHeight);
739 listBox.modifiedDocument = true;
742 listBox.CheckConsistency();
752 return AddRowAfter(subRows.last);
756 DataRow AddStringf(char * format, ...)
761 char string[MAX_F_STRING];
763 va_start(args, format);
764 vsnprintf(string, sizeof(string), format, args);
765 string[sizeof(string)-1] = 0;
769 row.SetData(null, string);
775 DataRow AddString(char * string)
781 row.SetData(listBox.fields.first, string);
791 subRows.offset = (uint)&((DataRow)0).prev;
796 ListBoxCell cell, next;
801 while((subRow = subRows.first))
803 subRows.Remove(subRow);
807 for(cell = cells.first; cell; cell = next, cellIndex++)
812 for(field = listBox.fields.first; field && field.index != cellIndex; field = field.next);
815 // TOCHECK: Is this check good? Will need incref/decref sometime?
816 if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
818 if(cell.data[0] && field.freeData)
819 field.dataType._vTbl[__ecereVMethodID_class_OnFree](field.dataType, cell.data[0]);
822 field.dataType._vTbl[__ecereVMethodID_class_OnFree](field.dataType, cell.data);
832 return !this || (!collapsed && (!parent || parent.IsExpanded()));
835 int Compare(DataRow b, DataField sortField)
838 ListBoxCell cell1, cell2;
840 for(index = 0, cell1 = cells.first, cell2 = b.cells.first;
841 index != sortField.index;
842 index++, cell1 = cell1.next, cell2 = cell2.next);
844 if(!cell1.isSet && !cell2.isSet)
846 else if(!cell1.isSet)
848 else if(!cell2.isSet)
851 if(noneRow && !b.noneRow) return -1;
852 else if(!noneRow && b.noneRow) return 1;
853 else if(noneRow && b.noneRow) return 0;
855 if(sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare])
857 if(sortField.dataType.type == normalClass || sortField.dataType.type == noHeadClass)
859 result = sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare](sortField.dataType,
860 (cell1.isSet && cell1.data) ? cell1.data[0] : null,
861 (cell2.isSet && cell2.data) ? cell2.data[0] : null);
865 result = sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare](sortField.dataType,
866 cell1.isSet ? cell1.data : null,
867 cell2.isSet ? cell2.data : null);
870 return sortField.sortOrder * result;
873 void _SortSubRows(DataField field, int order)
876 for(search = subRows.first; search; search = search.next)
877 search._SortSubRows(field, order);
878 subRows.Sort(Compare, field);
881 public void SortSubRows(bool scrollToCurrent)
883 if(this && listBox && listBox.sortField)
885 _SortSubRows(listBox.sortField, listBox.sortField.sortOrder);
889 int index = this.index;
890 for(search = this; search; search = search.GetNextRow())
891 search.index = index++;
895 int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
896 int height = listBox.clientSize.h + 1 - headerSize;
897 if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
898 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
899 else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
900 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0);
901 listBox.OnVScroll(0, listBox.scroll.y, 0);
906 public DataRow GetPrevRow()
912 for(row = prev; row && !row.collapsed && row.subRows.last; row = row.subRows.last);
919 public DataRow GetNextRow()
923 if(subRows.first && !collapsed)
927 for(row = this; row; row = row.parent)
929 if(row.next) { row = row.next; break; }
935 private DataRow GetLastRow()
938 while(row && !row.collapsed && row.subRows.last)
939 row = row.subRows.last;
946 SelectedFlag selectedFlag;
957 public class ListBox : CommonControl
959 hasVertScroll = true;
960 // background = white;
962 snapVertScroll = true;
964 class_property(icon) = "<:ecere>controls/listBox.png";
968 property bool freeSelect { property_category $"Behavior" set { style.freeSelect = value; } get { return style.freeSelect; } };
969 property DataRow currentRow { property_category $"Private" /*"Behavior"*/ set { SetCurrentRow(value, false); } get { return currentRow; } };
970 property DataField currentField
972 get { return currentField; }
973 // TODO: Document what this does
976 currentField = value;
977 HideEditBox(true, true, false);
978 if(value && value.editable)
979 PopupEditBox(currentField, false);
983 property int rowHeight
985 property_category $"Appearance"
986 isset { return style.heightSet; }
991 style.heightSet = true;
993 SetScrollLineStep(8, value);
997 style.heightSet = false;
1002 get { return rowHeight; }
1004 property Seconds typingTimeout
1006 property_category $"Behavior"
1009 typedString[0] = '\0';
1010 typingTimer.delay = value;
1011 typingTimeOut = value;
1013 get { return typingTimeOut; }
1015 property bool moveRows { property_category $"Behavior" set { style.moveRows = value; } get { return style.moveRows; } };
1016 property bool moveFields { property_category $"Behavior" set { style.moveFields = value; } get { return style.moveFields; } };
1017 property bool resizable { property_category $"Behavior" set { style.resizable = value; } get { return style.resizable; } };
1018 property bool autoScroll { property_category $"Behavior" set { style.autoScroll = value; } get { return style.autoScroll; } };
1019 property bool alwaysHighLight { property_category $"Appearance" set { style.alwaysHL = value; } get { return style.alwaysHL; } };
1020 property bool hasClearHeader { property_category $"Appearance" set { style.clearHeader = value; if(value) property::hasHeader = true; } get { return style.clearHeader; } };
1021 property bool hasHeader
1023 property_category $"Appearance"
1026 if(value && !style.header)
1032 bevel = !guiApp.textMode && !style.clearHeader;
1033 dontScrollVert = true;
1036 NotifyPushed = HeaderPushed;
1037 NotifyClicked = HeaderClicked;
1038 NotifyDoubleClick = HeaderDoubleClicked;
1039 NotifyReleased = HeaderReleased;
1040 NotifyMouseMove = HeaderMouseMove;
1044 endBevel.visible = false;
1046 style.header = value;
1048 get { return style.header; }
1050 property bool multiSelect { property_category $"Behavior" set { style.multiSelect = value; } get { return style.multiSelect; } };
1051 property bool alwaysEdit { property_category $"Behavior" set { style.alwaysEdit = value; } get { return style.alwaysEdit; } };
1052 property bool fullRowSelect { property_category $"Appearance" set { style.fullRowSelect = value; } get { return style.fullRowSelect; } };
1053 property bool collapseControl { property_category $"Appearance" set { style.collapse = value; } get { return style.collapse; } };
1054 property bool treeBranches { property_category $"Appearance" set { style.treeBranch = value; } get { return style.treeBranch; } };
1055 property bool rootCollapseButton { property_category $"Appearance" set { style.rootCollapse = value; } get { return style.rootCollapse; } };
1056 property bool sortable { property_category $"Behavior" set { style.sortable = value; } get { return style.sortable; } };
1057 property bool noDragging { property_category $"Behavior" set { style.noDragging = value; } get { return style.noDragging; } };
1058 property bool fillLastField
1060 property_category $"Behavior"
1063 style.fillLastField = value;
1065 get { return style.fillLastField; }
1067 property int numSelections
1071 int numSelections = 0;
1072 if(this && style.multiSelect)
1075 for(row = rows.first; row; row = row.GetNextRow())
1076 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
1079 return numSelections;
1082 property int currentIndex
1084 get { return currentRow ? currentRow.index : -1; }
1086 property DataRow lastRow { get { return this ? rows.last : null; } };
1087 property DataRow firstRow { get { return this ? rows.first : null; } };
1088 property int rowCount { get { return rowCount; } };
1089 property DataField firstField { get { return this ? fields.first : null; } };
1090 property Color selectionColor { set { selectionColor = value; } get { return selectionColor; } isset { return selectionColor ? true : false; } };
1091 property Color selectionText { set { selectionText = value; } get { return selectionText; } isset { return selectionText ? true : false; } };
1092 property Color stippleColor { set { stippleColor = value; } get { return stippleColor; } };
1093 property bool expandOnAdd { set { style.expandOnAdd = value; } get { return style.expandOnAdd; } };
1096 virtual bool Window::NotifySelect(ListBox listBox, DataRow row, Modifiers mods);
1097 virtual bool Window::NotifyHighlight(ListBox listBox, DataRow row, Modifiers mods);
1098 virtual bool Window::NotifyReclick(ListBox listBox, DataRow row, Modifiers mods);
1099 virtual bool Window::NotifySort(ListBox listBox, DataField field, Modifiers mods);
1100 virtual bool Window::NotifyChanged(ListBox listBox, DataRow row);
1101 virtual bool Window::NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch);
1102 virtual bool Window::NotifyEdited(ListBox listBox, DataRow row);
1103 virtual bool Window::NotifyEditDone(ListBox listBox, DataRow row);
1104 virtual bool Window::NotifyMovedField(ListBox listBox, DataField field, Modifiers mods);
1105 virtual bool Window::NotifyMove(ListBox listBox, DataRow row, Modifiers mods);
1106 virtual bool Window::NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods);
1107 virtual bool Window::NotifyRightClick(ListBox listBox, int x, int y, Modifiers mods);
1108 virtual bool Window::NotifyResized(ListBox listBox, DataField field, Modifiers mods);
1109 virtual bool Window::NotifyCollapse(ListBox listBox, DataRow row, bool collapsed);
1110 virtual bool Window::NotifyKeyHit(ListBox listBox, DataRow row, Key key, unichar ch);
1111 virtual bool Window::NotifyModified(ListBox listBox, DataRow row);
1112 virtual bool Window::NotifyEditing(ListBox listBox, DataRow row);
1115 private void CheckConsistency()
1120 for(r = rows.first; r; r = r.GetNextRow())
1122 if(r.index != index++)
1130 void AddField(DataField addedField)
1135 if(fields.first && ((DataField)fields.first).defaultField)
1137 DataField defaultField = fields.first;
1138 defaultField.Free();
1139 delete defaultField;
1143 addedField = DataField { };
1147 addedField.listBox = this;
1148 fields.Add(addedField);
1150 addedField.sortOrder = 1;
1151 addedField.index = numFields;
1155 addedField.headButton.Destroy(0);
1156 delete addedField.headButton;
1157 addedField.headButton = Button
1162 dontScrollVert = true;
1163 id = (uint64)addedField;
1164 text = addedField.header;
1165 bevel = (!guiApp.textMode && !style.clearHeader);
1167 alignment = addedField.alignment;
1168 NotifyPushed = HeaderPushed;
1169 NotifyClicked = HeaderClicked;
1170 NotifyDoubleClick = HeaderDoubleClicked;
1171 NotifyReleased = HeaderReleased;
1172 NotifyMouseMove = HeaderMouseMove;
1174 incref addedField.headButton;
1175 addedField.headButton.Create();
1178 addedField.headButton.background = Color { 0, 170, 0 };
1184 for(row = rows.first; row; )
1186 int size = (field.dataType && field.dataType.typeSize) ?
1187 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1188 ListBoxCell cell = (ListBoxCell)new0 byte[size];
1189 row.cells.Add(cell);
1190 FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
1193 if(row.subRows.first)
1194 row = row.subRows.first;
1197 for(; row; row = row.parent)
1199 if(row.next) { row = row.next; break; }
1204 OnResize(clientSize.w, clientSize.h);
1213 while((field = fields.first))
1219 endBevel.visible = false;
1224 void RemoveField(DataField field)
1230 int index = field.index;
1233 if(sortField == field)
1236 for(row = rows.first; row; )
1241 for(cell = row.cells.first, c = 0; c < index && cell; c++, cell = cell.next);
1242 if(cell && index == c)
1246 // TOCHECK: Is this check good? Will need incref/decref sometime?
1247 if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
1249 if(cell.data[0] && field.freeData)
1250 field.dataType._vTbl[__ecereVMethodID_class_OnFree](field.dataType, cell.data[0]);
1253 field.dataType._vTbl[__ecereVMethodID_class_OnFree](field.dataType, cell.data);
1256 row.cells.Remove(cell);
1260 if(row.subRows.first)
1261 row = row.subRows.first;
1264 for(; row; row = row.parent)
1266 if(row.next) { row = row.next; break; }
1275 endBevel.visible = false;
1279 DataRow AddRowNone()
1281 DataRow row { noneRow = true };
1290 rows.Insert(null, row);
1293 for(search = row.GetNextRow(); search; search = search.GetNextRow())
1299 firstRowShown = row;
1303 (rowCount * rowHeight) +
1304 ((style.header) ? rowHeight : 0) -
1305 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1306 if(style.autoScroll)
1307 SetScrollPosition(0, MAXINT - rowHeight);
1308 modifiedDocument = true;
1327 // Find very last row
1330 for(lastRow = rows.last; lastRow && !lastRow.collapsed && lastRow.subRows.last; lastRow)
1331 lastRow = lastRow.subRows.last;
1332 row.index = lastRow ? (lastRow.index + 1) : 0;
1340 for(c = 0; c<fields.count; c++)
1342 for(field = fields.first; field; field = field.next)
1343 if((int)field.index == c)
1347 int size = (field.dataType && field.dataType.typeSize) ?
1348 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1349 ListBoxCell cell = (ListBoxCell) new0 byte[size];
1350 row.cells.Add(cell);
1351 FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
1358 firstRowShown = row;
1364 (rowCount * rowHeight) +
1365 ((style.header) ? rowHeight : 0) -
1366 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1367 if(style.autoScroll)
1368 SetScrollPosition(0, MAXINT - rowHeight);
1369 modifiedDocument = true;
1380 DataRow AddRowAfter(DataRow after)
1392 if(after && after.subRows.first && !after.collapsed)
1394 for(search = after.subRows.last; !search.collapsed && search.subRows.last; )
1395 search = search.subRows.last;
1396 row.index = search.index + 1;
1399 row.index = after ? (after.index + 1) : 0;
1400 rows.Insert(after, row);
1403 for(search = row.GetNextRow(); search; search = search.GetNextRow())
1408 for(c = 0; c<fields.count; c++)
1410 for(field = fields.first; field; field = field.next)
1411 if((int)field.index == c)
1415 int size = (field.dataType && field.dataType.typeSize) ?
1416 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1417 ListBoxCell cell = (ListBoxCell) new0 byte[size];
1418 row.cells.Add(cell);
1419 FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
1423 if(!firstRowShown || !after)
1425 firstRowShown = row;
1430 (rowCount * rowHeight) +
1431 ((style.header) ? rowHeight : 0) -
1432 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1433 if(style.autoScroll)
1434 SetScrollPosition(0, MAXINT - rowHeight);
1435 modifiedDocument = true;
1445 DataRow AddStringf(char * format, ...)
1451 char string[MAX_F_STRING];
1454 va_start(args, format);
1455 vsnprintf(string, sizeof(string), format ? format : "", args);
1456 string[sizeof(string)-1] = 0;
1460 row.SetData(fields.first, string);
1466 DataRow AddString(char * string)
1472 row.SetData(fields.first, string);
1478 void SelectRow(DataRow row)
1480 SetCurrentRow(row, true);
1483 void DeleteRow(DataRow row)
1485 if(!row) row = currentRow;
1488 DataRow sub, next, search;
1489 // Trying to move this here (Messed up deleting watches)
1490 //HideEditBox(false, false, true);
1493 for(sub = row.subRows.first; sub; sub = next)
1499 if(row.parent.IsExpanded())
1501 for(search = row.GetNextRow(); search; search = search.GetNextRow())
1506 HideEditBox(false, false, true);
1508 if(row == clickedRow)
1510 clickedRow = row.GetNextRow();
1512 clickedRow = row.GetPrevRow();
1515 if(row == currentRow)
1517 DataRow newCurrentRow = row.GetNextRow();
1519 newCurrentRow = row.GetPrevRow();
1520 SetCurrentRow(newCurrentRow, true);
1523 if(row == firstRowShown)
1525 firstRowShown = row.GetPrevRow();
1527 firstRowShown = row.GetNextRow();
1530 (row.parent ? row.parent.subRows: rows).Remove(row);
1533 //HideEditBox(false, false, true);
1537 (this.rowCount * rowHeight) +
1538 ((style.header) ? rowHeight : 0) -
1539 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1541 modifiedDocument = true;
1550 DataRow FindRow(int64 tag)
1555 for(row = rows.first; row; row = row.next)
1557 if(!row.noneRow && row.tag == tag)
1565 DataRow FindString(char * searchedString)
1568 bool checkNextField = true;
1569 int len = searchedString ? strlen(searchedString) : 0;
1571 for(field = fields.first; field; field = field.next)
1573 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1576 for(row = rows.first; row; row = row.GetNextRow())
1580 void * data = row.GetData(field);
1581 char tempString[1024] = "";
1582 bool needClass = false;
1583 char * string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass);
1585 if(string && string[0])
1586 checkNextField = false;
1587 if(string && string[0] && !strcmp(string, searchedString))
1592 if(!checkNextField) break;
1597 DataRow FindSubString(char * subString)
1600 bool checkNextField = true;
1601 int len = subString ? strlen(subString) : 0;
1605 for(field = fields.first; field; field = field.next)
1607 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1610 for(row = rows.first; row; row = row.GetNextRow())
1614 void * data = row.GetData(field);
1615 char tempString[1024] = "";
1616 bool needClass = false;
1617 char * string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass);
1619 if(string && string[0])
1620 checkNextField = false;
1621 if(string && string[0] && !strncmp(string, subString, len))
1626 if(!checkNextField) break;
1632 DataRow FindSubStringi(char * subString)
1635 bool checkNextField = true;
1636 int len = subString ? strlen(subString) : 0;
1637 DataRow result = null;
1638 char * bestResult = null;
1643 for(field = fields.first; field; field = field.next)
1645 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1648 for(row = rows.first; row; row = row.GetNextRow())
1652 void * data = row.GetData(field);
1653 char tempString[1024] = "";
1654 bool needClass = false;
1655 char * string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass);
1657 if(string && string[0])
1658 checkNextField = false;
1659 if(string && string[0])
1661 int stringLen = strlen(string);
1663 if(!strnicmp(string, subString, Min(len, stringLen)))
1665 if(bestLen < Min(len, stringLen))
1667 if(!bestResult || strcmpi(string, bestResult) < 0)
1669 bestLen = Min(len, stringLen);
1670 bestResult = string;
1678 if(!checkNextField) break;
1684 DataRow FindSubStringAfter(DataRow after, char * subString)
1687 bool checkNextField = true;
1688 int len = subString ? strlen(subString) : 0;
1692 for(field = fields.first; field; field = field.next)
1694 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1697 for(row = after.GetNextRow(); row && row != after; row = row.GetNextRow(), (!row) ? (row = rows.first) : null)
1701 void * data = row.GetData(field);
1702 char tempString[1024] = "";
1703 bool needClass = false;
1704 char * string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass);
1706 if(string && string[0])
1707 checkNextField = false;
1708 if(string && string[0] && !strncmp(string, subString, len))
1713 if(!checkNextField) break;
1719 DataRow FindSubRow(int64 tag)
1725 for(row = rows.first; row; row = row.next)
1727 if(!row.noneRow && row.tag == tag)
1729 if(!row.noneRow && row.subRows.first)
1731 DataRow subRow = row.FindSubRow(tag);
1745 Window master = this.master;
1747 HideEditBox(false, true, false);
1748 editData.Destroy(0);
1750 firstRowShown = currentRow = null;
1755 if(style.freeSelect)
1756 NotifyHighlight(master, this, currentRow ? currentRow : null, 0);
1758 NotifySelect(master, this, currentRow ? currentRow : null, 0);
1761 if(style.alwaysEdit && currentRow)
1762 currentRow.Edit(currentField);
1769 (this.rowCount * rowHeight) +
1770 ((style.header) ? rowHeight : 0) -
1771 ((rowHeight && !((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1776 void Sort(DataField field, int order)
1781 int headerSize = ((style.header) ? rowHeight : 0);
1782 int height = clientSize.h + 1 - headerSize;
1784 if(!field) field = fields.first;
1786 field.sortOrder = order ? order : 1;
1787 rows.Sort(DataRow::Compare, field);
1789 for(search = rows.first; search; search = search.next)
1790 search._SortSubRows(field, order);
1794 for(search = rows.first; search; search = search.GetNextRow())
1795 search.index = index++;
1798 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
1799 SetScrollPosition(scroll.x, currentRow.index * rowHeight - height + rowHeight);
1800 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
1801 SetScrollPosition(scroll.x, currentRow ? currentRow.index * rowHeight : 0);
1803 OnVScroll(0, scroll.y, 0);
1805 // SetScrollPosition(0, scroll.y);
1810 void StopEditing(bool save)
1812 HideEditBox(save, false, true);
1815 void GetMultiSelection(OldList list)
1818 if(this && style.multiSelect)
1822 for(row = rows.first; row; row = row.GetNextRow())
1824 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
1826 list.Add(OldLink { data = row });
1832 // Convenience Current Row Methods
1833 void * SetData(DataField field, any_object data)
1835 return currentRow.SetData(field, data);
1838 any_object GetData(DataField field)
1840 return (void *)currentRow.GetData(field);
1845 return currentRow ? currentRow.tag : 0;
1851 DataField defaultField { };
1852 rows.offset = (uint)&((DataRow)0).prev;
1853 fields.offset = (uint)&((DataField)0).prev;
1854 style.fullRowSelect = true;
1855 style.fillLastField = true;
1856 style.expandOnAdd = true;
1857 typingTimeOut = 0.5;
1858 rowHeight = 16; // Stuff depending on creation and default property checking
1861 defaultField.defaultField = true;
1863 AddField(defaultField);
1865 typedString = new char[1];
1866 typedString[0] = '\0';
1881 while((field = fields.first))
1883 // fields.Remove(field);
1893 while((row = rows.first))
1900 ListBoxCell GetCell(DataRow * row, DataField * field)
1902 ListBoxCell cell = null;
1903 if(!*row) *row = currentRow;
1906 if(!*field) *field = this ? currentField : null;
1909 for(*field = fields.first; (*field).index != 0; *field = (*field).next);
1914 if(field->listBox == this)
1916 for(index = 0, cell = (*row).cells.first; cell && index != (*field).index; index++, cell = cell.next);
1923 void HideEditBox(bool save, bool alwaysStopEdit, bool repositionOnly)
1925 if(editData && editData.visible)
1927 Class dataType = currentField.dataType;
1929 editData.SaveData();
1931 editData.visible = false;
1932 NotifyEditDone(master, this, currentRow);
1934 // ENSURE DATA BOX IS NOT VISIBLE
1935 editData.visible = false;
1937 if(style.alwaysEdit && !alwaysStopEdit)
1940 int height = rowHeight - (style.alwaysEdit ? 1 : 0);
1941 int y = currentRow.index * rowHeight + (style.header ? rowHeight : 0);
1942 int x = currentField.x;
1943 int width = (!currentField.next && style.fillLastField && (!hasHorzScroll || clientSize.w - currentField.x > currentField.width + EXTRA_SPACE)) ?
1944 clientSize.w - currentField.x : (currentField.width + EXTRA_SPACE);
1946 if(!style.alwaysEdit)
1948 editData.position = { x, y };
1949 editData.size = { width, height };
1953 editData.position = { x, y - editData.clientStart.y };
1954 editData.size = { width, height + editData.clientStart.y * 2 };
1956 editData.visible = true;
1957 if(style.alwaysEdit)
1958 editData.Deactivate();
1960 PopupEditBox(currentField, repositionOnly);
1966 currentField = null;*/
1970 void SetCurrentRow(DataRow row, bool notify)
1972 if(currentRow != row || (currentRow && currentRow.selectedFlag == unselected))
1974 int headerSize = ((style.header) ? rowHeight : 0);
1975 int height = clientSize.h + 1 - headerSize;
1977 // true: destroy edit box
1978 HideEditBox(true, true, false);
1980 if(!(style.multiSelect) && currentRow)
1981 currentRow.selectedFlag = unselected;
1985 if(style.multiSelect)
1989 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
1990 selRow.selectedFlag = unselected;
1992 currentRow.selectedFlag = selected;
1997 currentRow.selectedFlag = selected;
1999 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
2000 SetScrollPosition(scroll.x,
2001 currentRow.index * rowHeight - height + rowHeight);
2002 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
2004 int line = currentRow ? currentRow.index * rowHeight : 0;
2005 //SNAPUP(line, rowHeight);
2006 SetScrollPosition(scroll.x, line);
2011 Window master = this.master;
2014 if(style.freeSelect && visible)
2015 NotifyHighlight(master, this, currentRow ? currentRow : null, 0);
2017 NotifySelect(master, this, currentRow ? currentRow : null, 0);
2018 if(style.alwaysEdit && currentRow)
2019 currentRow.Edit(currentField);
2027 void PopupEditBox(DataField whichField, bool repositionOnly)
2029 if((!editData || !editData.visible || currentField != whichField) && currentRow)
2031 // true: destroy edit box
2032 HideEditBox(true, true, false);
2035 int height = rowHeight - (style.alwaysEdit ? 1 : 0);
2037 int y = currentRow.index * rowHeight + (style.header ? rowHeight : 0);
2039 //void * data = currentRow.GetData(whichField);
2044 if(style.collapse && !(style.treeBranch))
2047 for(field = fields.first; field; field = field.next)
2049 width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2050 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2051 if(field == whichField) break;
2055 currentField = whichField;
2056 cell = GetCell(&row, ¤tField);
2063 background = dataBoxBackground;
2064 foreground = dataBoxForeground;
2066 bool NotifyChanged(bool closingDropDown)
2069 DataField field = null;
2070 ListBoxCell cell = GetCell(&row, &field);
2074 modifiedDocument = true;
2076 NotifyChanged(master, this, currentRow);
2081 bool NotifyModified()
2083 //DataRow row = null;
2084 //DataField field = null;
2085 //ListBoxCell cell = GetCell(&row, &field);
2086 //cell.isSet = true;
2087 modifiedDocument = true;
2089 NotifyModified(master, this, currentRow);
2093 bool OnKeyDown(Key key, unichar ch)
2095 bool result = DataBox::OnKeyDown(key, ch);
2096 if(visible && active) // Added this check here, because we will not use enter/escape otherwise, and lose DataBox's result
2098 if((SmartKey)key == enter || (SmartKey)key == escape)
2107 editData.Destroy(0);
2108 editData.type = whichField.dataType;
2109 editData.fieldData = whichField.userData;
2110 editData.borderStyle = style.alwaysEdit ? 0 : deep;
2111 editData.data = cell ? cell.data : null;
2114 // Might not really need this anymore...
2115 NotifyEditing(master, this, currentRow);
2118 if(!style.alwaysEdit)
2120 editData.position = { x, y - editData.clientStart.y };
2121 editData.size = { width, height + editData.clientStart.y * 2 };
2125 editData.position = { x, y };
2126 editData.size = { width, height };
2130 editData.visible = true;
2132 if(style.alwaysEdit)
2133 editData.Deactivate();
2135 // MOVED THIS HIGHER FOR DATALIST EDITOR
2137 // Might not really need this anymore...
2138 NotifyEdited(master, this, currentRow);
2143 void OnRedraw(Surface surface)
2146 int y = (style.header) ? rowHeight : 0;
2147 bool isActive = active;
2148 Font font = fontObject;
2149 Font boldFont = this.boldFont.font;
2153 if(style.alwaysEdit && style.fullRowSelect)
2156 int y = (style.header) ? rowHeight : 0;
2157 int x = -scroll.x - 1;// + EXTRA_SPACE;// / 2 - 1;
2158 int w = clientSize.w;
2159 int h = clientSize.h;
2163 // Fill out indent column
2164 if(style.collapse && !(style.treeBranch) && rows.first)
2167 surface.SetBackground(formColor);
2168 surface.Area(-scroll.x, 0, x, clientSize.h);
2171 surface.SetForeground(formColor);
2172 for(row = firstRowShown; row; row = row.GetNextRow())
2175 surface.HLine(x + 1, w-1, y-1);
2181 for(field = fields.first; field; field = field.next)
2183 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2184 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2185 if(field.prev && y > 0)
2186 surface.VLine(0, y-1, x);
2191 surface.foreground = this.foreground;
2192 surface.TextOpacity(false);
2194 // Draw the tree branches
2195 if(style.treeBranch)
2197 int y = -scroll.y + ((style.header) ? rowHeight : 0);
2198 surface.LineStipple(0x5555);
2199 surface.SetForeground(branchesColor);
2200 for(row = rows.first; row; row = row.GetNextRow() )
2202 int x = -scroll.x + EXTRA_SPACE / 2-1;
2203 int rowStart = -scroll.x;
2208 for(parent = row.parent; parent; parent = parent.parent)
2209 if(!parent.header) indent += 20;
2210 if(style.rootCollapse) indent += 20;
2212 plusIndent = (style.treeBranch) ? (indent - 20 + 4) : indent;
2217 if(row.subRows.first)
2220 int y1 = y + PLUSY + 4;
2224 for(child = row.collapsed ? null : row.subRows.first; child && child != row; )
2227 if(child.subRows.first && !child.collapsed && child != row.subRows.last)
2228 child = child.subRows.first;
2233 for(; child && child != row; child = child.parent)
2243 y2 = y + numRows * rowHeight + PLUSY + 4;
2244 surface.VLine(y1, y2, rowStart + plusIndent + 7 + 20);
2246 surface.HLine(rowStart + plusIndent + 7, rowStart + indent, y + PLUSY + 4);
2249 if(y >= clientSize.h)
2252 // Root Vertical Lines
2253 if(style.rootCollapse && rows.first)
2258 y = -scroll.y + ((style.header) ? rowHeight : 0);
2260 for(child = rows.first; child && child != rows.last; )
2263 if(child.subRows.first && !child.collapsed && child != rows.last)
2264 child = child.subRows.first;
2269 for(; child; child = child.parent)
2279 y2 = y + numRows * rowHeight + PLUSY + 4;
2280 surface.VLine(y1, y2, -scroll.x + 11);
2282 surface.LineStipple(0);
2285 for(row = firstRowShown; row; row = row.GetNextRow() )
2287 int x = -scroll.x + EXTRA_SPACE / 2-1;
2290 Color foreground = this.foreground /*black*/, background = this.background /*white*/;
2291 DataDisplayFlags dataDisplayFlags = 0;
2292 int rowStart = -scroll.x;
2295 Bitmap icon = row.icon ? row.icon.bitmap : null;
2296 int collapseRowStart;
2297 bool lastWasHeader = row.header;
2299 for(parent = row.parent; parent; parent = parent.parent)
2301 if(!parent.header || lastWasHeader)
2303 if(style.treeBranch)
2309 if(style.rootCollapse) indent += 20;
2312 dataDisplayFlags.fullRow = style.fullRowSelect;
2313 dataDisplayFlags.active = isActive;
2314 dataDisplayFlags.header = row.header;
2319 collapseRowStart = rowStart;
2321 if(!(style.treeBranch))
2328 if(style.multiSelect)
2330 dataDisplayFlags.selected = row.selectedFlag == selected || row.selectedFlag == tempSelected;
2331 dataDisplayFlags.current = row == currentRow || (!currentRow && row == firstRowShown);
2335 dataDisplayFlags.selected = row.selectedFlag == selected || row.selectedFlag == tempSelected;
2336 dataDisplayFlags.current = row == currentRow || (!currentRow && row == firstRowShown);
2338 if(row == currentRow)
2340 dataDisplayFlags.current = true;
2341 dataDisplayFlags.selectedFlag = true;
2343 else if(!currentRow && row == firstRowShown)
2345 dataDisplayFlags.current = true;
2349 surface.TextOpacity(true);
2351 background = this.background;
2352 foreground = this.foreground;
2354 // Draw the current row background
2357 Color colors[] = { formColor, azure, mistyRose, linen, floralWhite, lavender, lavenderBlush, lemonChiffon };
2360 while(p = p.parent) level++;
2361 background = colors[(level % (sizeof(colors)/sizeof(colors[0]))];
2362 surface.SetBackground(background);
2363 surface.Area(rowStart, y, clientSize.w, (y + rowHeight) - 1);
2364 foreground = branchesColor;
2366 else if(dataDisplayFlags.selected)
2368 if(dataDisplayFlags.selected && (isActive || style.alwaysHL || (style.alwaysEdit && style.fullRowSelect)))
2370 if(!isActive && style.alwaysEdit)
2371 background = formColor;
2373 background = selectionColor ? selectionColor : SELECTION_COLOR;
2374 if(style.fullRowSelect)
2376 int offset = (style.alwaysEdit) ? 2 : 1;
2377 surface.SetBackground(background);
2378 surface.Area(rowStart, y, clientSize.w, (y + rowHeight) - offset);
2380 if(isActive || !(style.alwaysEdit))
2381 foreground = selectionText ? selectionText : SELECTION_TEXT;
2383 foreground = branchesColor;
2389 surface.Blit(icon, x + (20 - icon.width) /2,y + 2,0,0, icon.width, icon.height);
2395 int width = clientSize.w;
2397 dataDisplayFlags.firstField = true;
2398 clip.left = x - EXTRA_SPACE / 2+1;
2400 clip.right = x + width - EXTRA_SPACE/2 - 0;
2401 clip.bottom = y + rowHeight - 1;
2402 surface.Clip(&clip);
2404 surface.TextFont(font);
2406 surface.SetForeground(foreground);
2407 surface.SetBackground(background);
2409 class(String)._vTbl[__ecereVMethodID_class_OnDisplay](class(String), "(none)", surface, x, y - 1 + (rowHeight - fontH)/2, width - EXTRA_SPACE/2, null, Alignment::left, dataDisplayFlags);
2413 if(!opacity) surface.TextOpacity(false);
2415 for(field = fields.first; field; field = field.next)
2418 int width = ((!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) || row.header) ?
2419 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2421 // Box clip = { x, y+1, x + field.width - EXTRA_SPACE - 1, y + rowHeight - 2 };
2424 //width -= EXTRA_SPACE;
2426 if(!field.prev) width -= indent;
2429 dataDisplayFlags.firstField = field.prev ? false : true;
2431 if(!dataDisplayFlags.firstField && !dataDisplayFlags.fullRow)
2433 background = this.background;
2434 foreground = this.foreground;
2437 if(!isActive && dataDisplayFlags.selected && style.alwaysEdit && field.editable && opacity)
2440 surface.SetBackground(background);
2441 surface.Area(x-3, y, x+width-1, y + rowHeight-2);
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 for(index = 0, cell = row.cells.first; cell && index != field.index; index++, cell = cell.next);
2451 // Should always be as many cells in the row as fields in the listbox
2452 if(cell && cell.isSet && field.dataType)
2455 surface.TextFont(boldFont);
2457 surface.TextFont(font);
2459 surface.SetForeground(foreground);
2460 surface.SetBackground(background);
2462 if(field.dataType.type == noHeadClass || field.dataType.type == normalClass)
2463 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);
2465 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);
2468 if(!isActive && dataDisplayFlags.selected && style.alwaysEdit && field.editable)
2469 background = formColor;
2471 if(!dataDisplayFlags.firstField && !dataDisplayFlags.fullRow)
2473 background = formColor;
2474 foreground = this.background;
2477 x += width;// + EXTRA_SPACE;
2479 if(row.header) break;
2485 int plusIndent = (style.treeBranch) ? (indent - 20 + 4) : indent;
2487 if(row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)))
2489 surface.SetForeground(row.header ? headerCollapseForeground : this.foreground);
2490 surface.Rectangle(collapseRowStart + 3 + plusIndent, y + PLUSY, collapseRowStart + 11 + plusIndent, y + PLUSY + 8);
2492 surface.SetBackground(row.header ? (formColor) : (this.background)); //white
2493 surface.Area(collapseRowStart + 4 + plusIndent, y + PLUSY + 1, collapseRowStart + 10 + plusIndent, y + PLUSY + 7);
2495 surface.HLine(collapseRowStart + 5 + plusIndent, collapseRowStart + 9 + plusIndent, y+PLUSY+4);
2497 surface.VLine(y + PLUSY + 2, y + PLUSY + 6, collapseRowStart + 7 + plusIndent);
2502 // Draw the current row stipple
2503 if(style.fullRowSelect && !(style.alwaysEdit) && (dataDisplayFlags.current) && isActive)
2508 surface.LineStipple(0x5555);
2509 if(dataDisplayFlags.selected)
2510 surface.SetForeground(stippleColor);
2512 surface.SetForeground(this.foreground);
2515 surface.SetForeground(selectionColor ? selectionColor : SELECTION_COLOR);
2516 surface.Rectangle(0, y, clientSize.w-1, (y + rowHeight) - 1);
2517 surface.LineStipple(0);
2521 if(y >= clientSize.h)
2524 if(firstRowShown) surface.Clip(null);
2525 if(this.dragRow && this.dropIndex != -1)
2527 int dropIndex = this.dropIndex;
2530 if(!style.multiSelect && currentRow.index < this.dropIndex)
2532 surface.DrawingChar(223);
2534 y = style.header ? rowHeight : 0;
2535 y += dropIndex * rowHeight - scroll.y;
2537 surface.SetForeground(Color { 85, 85, 255 });
2538 surface.HLine(0, clientSize.w-1, y);
2539 surface.HLine(0, clientSize.w-1, y + 1);
2543 void OnDrawOverChildren(Surface surface)
2545 if(draggingField && this.dropField)
2547 int position = this.dropField.x;
2548 if(draggingField.x < position)
2549 position += this.dropField.width + EXTRA_SPACE;
2551 surface.SetForeground(Color { 85, 85, 255 });
2552 surface.VLine(0, rowHeight - 1, position - scroll.x - 2);
2553 surface.VLine(0, rowHeight - 1, position - scroll.x);
2555 if(sortField && !style.clearHeader && style.header)
2557 DataField field = sortField;
2558 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2559 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2562 surface.TextExtent(field.header, strlen(field.header), &tw, &th);
2563 if(tw < width - EXTRA_SPACE)
2565 bool up = field.sortOrder == 1;
2569 field.x + 2 - scroll.x, 0,
2570 field.x + width + EXTRA_SPACE - 1 - scroll.x, rowHeight
2572 surface.Clip(&clip);
2573 if(field.alignment == left || field.alignment == center)
2575 if(field.alignment == center)
2576 x = field.x + (width + EXTRA_SPACE - tw) / 2 + tw + EXTRA_SPACE + 4;
2578 x = field.x + tw + EXTRA_SPACE + 4;
2580 x = Min(x, field.x + width - 4);
2582 else if(field.alignment == right)
2584 x = field.x + width - tw - 2*EXTRA_SPACE - 4;
2585 x = Max(x, field.x + 2);
2591 // surface.SetForeground((wmenu.selectedFlag == item) ? white : black);
2592 // surface.WriteText(clientSize.w-8, y+(wmenu.rh - 8)/2, "\020", 1);
2598 surface.SetForeground(Color { 128,128,128 } );
2599 surface.DrawLine(x + 3, y, x, y + 5);
2600 surface.PutPixel(x + 1, y + 5);
2601 surface.PutPixel(x + 1, y + 3);
2602 surface.PutPixel(x + 2, y + 1);
2604 surface.SetForeground(white);
2605 surface.DrawLine(x + 4, y, x + 7, y + 5);
2606 surface.PutPixel(x + 6, y + 5);
2607 surface.PutPixel(x + 6, y + 3);
2608 surface.PutPixel(x + 5, y + 1);
2610 surface.DrawLine(x, y + 6, x + 7, y + 6);
2614 surface.SetForeground(Color { 128,128,128 });
2615 surface.DrawLine(x + 3, y+6, x, y+1);
2616 surface.PutPixel(x + 1, y+1);
2617 surface.PutPixel(x + 1, y+3);
2618 surface.PutPixel(x + 2, y+5);
2620 surface.SetForeground(white);
2621 surface.DrawLine(x + 4, y+6, x + 7, y+1);
2622 surface.PutPixel(x + 6, y+1);
2623 surface.PutPixel(x + 6, y+3);
2624 surface.PutPixel(x + 5, y+5);
2626 surface.DrawLine(x, y, x + 7, y);
2635 void OnResize(int w, int h)
2638 bool showEndBevel = false;
2640 if(style.collapse && !style.treeBranch)
2642 for(field = fields.first; field; field = field.next)
2644 int width = field.width + EXTRA_SPACE;
2652 (rowCount * rowHeight) +
2653 ((style.header) ? rowHeight : 0) -
2654 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
2656 for(field = fields.first; field; field = field.next)
2658 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2659 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2660 if(style.header && field.headButton)
2662 showEndBevel = true;
2665 field.headButton.position = { field.x, 0 };
2666 field.headButton.size = { width, rowHeight };
2667 field.headButton.visible = true;
2670 field.headButton.visible = false;
2674 if(!style.fillLastField && showEndBevel && endBevel)
2676 endBevel.position = { x, 0 };
2677 endBevel.size = { clientSize.w + 2 - x, rowHeight };
2678 endBevel.visible = true;
2681 endBevel.visible = false;
2683 if(style.alwaysEdit && editData && editData.visible)
2685 HideEditBox(true, false, true);
2689 void AdaptToFieldWidth(DataField field, bool doScroll)
2691 OnResize(clientSize.w, clientSize.h);
2693 // Scroll appropriately
2696 if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x &&
2697 field.x >= field.x + field.width + EXTRA_SPACE - clientSize.w)
2699 SetScrollPosition(field.x + field.width + EXTRA_SPACE - clientSize.w, scroll.y);
2701 else if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x ||
2703 SetScrollPosition(field.x, scroll.y);
2708 bool HeaderPushed(Button control, int x, int y, Modifiers mods)
2710 DataField field = (DataField)control.id;
2711 // false: dont destroy edit box
2712 HideEditBox(true, false, true);
2713 if(style.resizable && ((!field && x < RESIZE_BORDER && fields.last) ||
2714 (field && x < RESIZE_BORDER && field.prev) ||
2715 (field && x >= control.clientSize.w - RESIZE_BORDER)))
2718 field = fields.last;
2719 else if(x < RESIZE_BORDER && field.prev)
2722 if(field.fixed) return false;
2723 resizingField = field;
2724 this.resizeX = x + control.position.x;
2725 this.startWidth = field.width;
2726 this.oldX = x - scroll.x;
2731 if(field.fixed) return false;
2732 draggingField = field;
2733 if(style.moveFields)
2734 field.headButton.stayDown = true;
2735 else if(!style.sortable)
2743 bool HeaderMouseMove(Button control, int x, int y, Modifiers mods)
2748 DataField field = resizingField;
2750 x += control.position.x;
2752 // Tweak to prevent shrinking field if we're actually moving right
2753 if(x - scroll.x > this.oldX &&
2754 this.startWidth + x - this.resizeX < field.width)
2756 this.oldX = x - scroll.x;
2759 this.oldX = x - scroll.x;
2761 field.width = this.startWidth + x - this.resizeX;
2762 field.width = Max(field.width, - EXTRA_SPACE);
2764 AdaptToFieldWidth(field, true);
2766 else if(draggingField)
2768 x += control.position.x;
2769 if(style.moveFields)
2771 DataField field = fields.last;
2773 for(field = fields.first; field; field = field.next)
2775 fieldX += ((field.width || style.resizable) ?
2776 field.width : clientSize.w) + EXTRA_SPACE;
2780 if(draggingField == field)
2782 // Reset scroll position
2783 if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x &&
2784 field.x >= field.x + field.width + EXTRA_SPACE - clientSize.w)
2787 field.x + field.width + EXTRA_SPACE - clientSize.w,
2790 else if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x ||
2792 SetScrollPosition(field.x, scroll.y);
2795 if(this.dropField != field)
2797 this.dropField = field;
2800 int position = field.x;
2802 if(draggingField.x < position)
2804 position += field.width + EXTRA_SPACE - clientSize.w;
2805 if(position > scroll.x)
2806 SetScrollPosition(position, scroll.y);
2811 if(position < scroll.x)
2812 SetScrollPosition(position, scroll.y);
2815 this.movingFields = true;
2821 else if(style.resizable)
2823 DataField field = (DataField)control.id;
2826 if(x < RESIZE_BORDER && field.prev)
2828 if(!field.prev.fixed)
2829 control.cursor = guiApp.GetCursor(sizeWE);
2831 else if(x >= control.clientSize.w - RESIZE_BORDER)
2832 control.cursor = guiApp.GetCursor(sizeWE);
2834 control.cursor = null;
2838 if(x < RESIZE_BORDER && fields.last)
2839 control.cursor = guiApp.GetCursor(sizeWE);
2841 control.cursor = null;
2847 bool HeaderReleased(Button control, int x, int y, Modifiers mods)
2851 NotifyResized(master, this, resizingField, mods);
2852 resizingField = null;
2859 if(style.moveFields)
2864 DataField switchField = fields.last;
2868 x += draggingField.x;
2869 for(field = fields.first; field; field = field.next)
2871 fieldX += ((field.width || style.resizable) ?
2872 field.width : clientSize.w) + EXTRA_SPACE;
2875 switchField = field;
2879 if(switchField && draggingField != switchField && this.dropField)
2881 for(field = fields.first; field; field = field.next)
2883 if(field == switchField || field == draggingField)
2887 // Switch field first: move before
2888 if(field == switchField)
2889 draggingField.Move(switchField.prev);
2890 // Dragged field first: move after
2892 draggingField.Move(switchField);
2894 NotifyMovedField(master, this, draggingField, mods);
2896 draggingField.headButton.stayDown = false;
2901 movingFields = false;
2903 draggingField = null;
2909 bool HeaderClicked(Button control, int x, int y, Modifiers mods)
2911 if(style.header && !this.dropField && style.sortable)
2913 DataField field = (DataField)control.id;
2914 if(sortField == field)
2915 field.sortOrder *= -1;
2920 Sort(sortField, field.sortOrder);
2921 NotifySort(master, this, field, mods);
2927 bool HeaderDoubleClicked(Button control, int x, int y, Modifiers mods)
2931 DataField field = (DataField)control.id;
2934 if(x < RESIZE_BORDER && field.prev)
2936 else if(x >= control.clientSize.w - RESIZE_BORDER);
2942 if(x < RESIZE_BORDER && fields.last)
2943 field = fields.last;
2955 if(style.freeSelect)
2960 this.rolledOver = this.dragging = false;
2967 bool OnLoadGraphics()
2969 display.FontExtent(fontObject, "W", 1, null, &fontH);
2970 if(!style.heightSet)
2972 rowHeight = Max(fontH + 2, 16) + (style.alwaysEdit ? 1 : 0);
2973 SetScrollLineStep(8, rowHeight);
2978 void OnApplyGraphics()
2980 SetScrollLineStep(8, rowHeight);
2984 for(field = fields.first; field; field = field.next)
2986 if(field.headButton)
2988 field.headButton.bevel = (!guiApp.textMode && !style.clearHeader);
2990 field.headButton.background = Color { 0, 170, 0 };
2994 OnResize(clientSize.w, clientSize.h);
2997 bool OnResizing(int *w, int *h)
3001 if(!initSize.w && (!anchor.left.type || !anchor.right.type) /**w*/)
3006 Font font = fontObject;
3007 Font boldFont = this.boldFont.font;
3008 Display display = this.display;
3010 for(row = rows.first; row; row = row.GetNextRow())
3012 Bitmap icon = row.icon ? row.icon.bitmap : null;
3013 int x = -scroll.x + EXTRA_SPACE / 2-1;
3017 for(parent = row.parent; parent; parent = parent.parent)
3021 if(style.treeBranch)
3027 if(style.rootCollapse) indent += 20;
3029 if(style.collapse && !(style.treeBranch)) x += 15;
3033 // Compute the rows size
3034 for(field = fields.first; field; field = field.next)
3036 if(((style.resizable && (!(style.alwaysEdit) || field.next)) || field.width) && !row.header)
3037 x += field.width - (field.prev ? 0 : indent);
3042 for(index = 0, cell = row.cells.first; index != field.index; index++, cell = cell.next);
3044 // Should always be as many cells in the row as fields in the listbox
3045 if(cell && cell.isSet && field.dataType)
3047 static char tempString[4096];
3050 if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
3051 string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, cell.data[0], tempString, field.userData, null);
3053 string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, cell.data, tempString, field.userData, null);
3055 if(!string) string = "";
3056 display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, &th);
3059 display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, &th);
3061 display.FontExtent(row.header ? boldFont : font, "", 0, &tw, &th);
3064 if(row.header) break;
3068 maxWidth = Max(maxWidth, x);
3074 *h = Min(this.maxShown, this.rowCount) * rowHeight;
3079 if(!*w) *w = rowHeight * 5;
3080 if(!*h) *h = rowHeight * 5;
3087 FontResource font = this.font;
3088 FontResource boldFont
3090 faceName = font.faceName, size = font.size, bold = true
3092 AddResource(boldFont);
3093 RemoveResource(this.boldFont);
3094 this.boldFont = boldFont;
3098 SetInitSize(initSize);
3101 bool OnMouseMove(int x, int y, Modifiers mods)
3103 bool isTimer = false;
3104 int realX = x, realY = y;
3106 if(insideNotifySelect) return true;
3108 if(style.alwaysEdit && style.resizable &&
3109 resizingField && !(mods.isSideEffect))
3112 DataField field = resizingField;
3113 field.width = this.startWidth + x - this.resizeX;
3114 field.width = Max(field.width, - EXTRA_SPACE);
3116 AdaptToFieldWidth(field, true);
3120 if(style.alwaysEdit && style.resizable)
3122 int vx = -scroll.x - 1;
3125 if(style.collapse && !(style.treeBranch))
3128 for(field = fields.first; field; field = field.next)
3130 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3131 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3137 cursor = guiApp.GetCursor(sizeWE);
3141 vx += width + EXTRA_SPACE;
3145 if((editData && editData.visible) || (style.alwaysEdit))
3148 if(x == MAXINT && y == MAXINT)
3155 // ADDED THIS CHECK FOR FieldDropBox LEAKS
3156 if(/*!mods.isSideEffect && */(this.rolledOver || !this.dragging))
3158 int rowY = (style.header) ? rowHeight : 0;
3166 ((vertScroll && vertScroll.visible &&
3167 (y < 0 || y >= clientSize.h)) ||
3168 (horzScroll && horzScroll.visible &&
3169 (x < 0 || x >= clientSize.w))))
3174 if(vertScroll && vertScroll.visible &&
3175 (y < 0 || y >= clientSize.h))
3176 vertScroll.Action((y<0)?up:down, 0, 0);
3177 if(horzScroll && horzScroll.visible &&
3178 (x < 0 || x >= clientSize.w))
3179 horzScroll.Action((x<0)?up:down, 0, 0);
3185 // This must be done after the scrolling took place
3186 rowIndex = firstRowShown ? firstRowShown.index : -1;
3188 y = Min(y, clientSize.h-1);
3189 for(row = firstRowShown; row; row = row.GetNextRow(), rowIndex ++)
3198 if(row && currentRow != row)
3200 if(this.dragRow && style.moveRows)
3202 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
3204 else if(style.multiSelect)
3207 for(thisRow = rows.first; thisRow; thisRow = thisRow.GetNextRow())
3208 if((thisRow.selectedFlag == selected || thisRow.selectedFlag == tempSelected) ||
3214 if(this.dropIndex != rowIndex)
3216 this.dropIndex = rowIndex;
3217 this.editRow = null;
3219 this.movedRow = true;
3222 else if((style.freeSelect || this.dragging) && ((realX>= 0 && realY >= 0 && realX< clientSize.w && realY < clientSize.h) || this.rolledOver))
3224 if(!(style.multiSelect))
3226 if(currentRow)currentRow.selectedFlag = unselected;
3227 if(row)row.selectedFlag = selected;
3231 if(style.multiSelect)
3235 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3237 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3238 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3241 if(rowIndex >= clickedRow.index)
3243 for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
3245 selRow.selectedFlag = (selRow.selectedFlag == selected) ? tempUnselected : tempSelected;
3252 for(selRow = row; selRow; selRow = selRow.GetNextRow())
3254 selRow.selectedFlag = (selRow.selectedFlag == selected) ? tempUnselected : tempSelected;
3255 if(selRow == clickedRow)
3261 if(style.freeSelect)
3262 NotifyHighlight(master, this, currentRow, mods);
3265 insideNotifySelect = true;
3266 NotifySelect(master, this, currentRow, mods);
3267 insideNotifySelect = false;
3270 if(style.alwaysEdit && currentRow)
3271 currentRow.Edit(currentField);
3278 bool OnMouseOver(int x, int y, Modifiers mods)
3281 this.rolledOver = true;
3285 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
3287 // TOCHECK: WAS THIS MISSING ? CHECK FOR SLOWDOWN
3288 if(!active) Update(null);
3290 if(!active && (!swap || !swap.isModal))
3292 // true: destroy edit box
3293 HideEditBox(true, true, false);
3295 else if(!swap || !swap.isModal)
3297 // Bring back edit box
3298 if(currentRow && style.alwaysEdit)
3300 currentRow.Edit(currentField ? currentField : null);
3304 return true; //NotifyActivate(master, this, active, swap, 0);
3308 bool OnButtonDown(int x, int y, Modifiers mods, bool right)
3311 // Check to see if we're dragging the vertical divider
3312 if(style.alwaysEdit && style.resizable && !right)
3314 int vx = -scroll.x - 1;// + EXTRA_SPACE;// / 2 - 1;
3317 if(style.collapse && !(style.treeBranch))
3320 for(field = fields.first; field; field = field.next)
3322 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3323 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3329 resizingField = field.prev;
3331 this.startWidth = resizingField.width;
3333 SetMouseRangeToClient();
3337 vx += width + EXTRA_SPACE;
3341 if(!(style.freeSelect))
3343 int rowY = (style.header) ? rowHeight : 0;
3345 int rowIndex = firstRowShown ? firstRowShown.index : -1;
3346 DataRow previousRow = currentRow;
3347 DataRow newCurrentRow = null;
3348 DataField newCurrentField = null;
3349 bool moveMultiple = false;
3350 int numSelected = 0;
3351 int rowStart = -scroll.x;
3353 if(style.multiSelect)
3360 for(row = rows.first; row; row = row.GetNextRow())
3362 if(row.selectedFlag == tempSelected)
3363 row.selectedFlag = selected;
3364 else if(row.selectedFlag == tempUnselected)
3365 row.selectedFlag = unselected;
3366 if(row.selectedFlag == selected)
3373 for(row = firstRowShown; row; row = row.GetNextRow(), rowIndex ++)
3376 if(rowY > y || (style.multiSelect && !row.GetNextRow()))
3379 if(style.treeBranch)
3382 for(parent = (style.rootCollapse) ? row.parent : (row.parent ? row.parent.parent : null); parent; parent = parent.parent)
3388 /* THIS WAS TOO STRICT:
3389 if(style.collapse && row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)) &&
3390 (x >= rowStart + 3 + plusIndent && y >= rowY - rowHeight + PLUSY && x <= rowStart + 11 + plusIndent && y <= rowY - rowHeight + PLUSY + 8))
3392 if(style.collapse &&
3393 (x >= rowStart && y >= rowY - rowHeight && x <= rowStart + 18 + plusIndent && y <= rowY + rowHeight-1))
3395 if(row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)) && x >= plusIndent)
3396 row.collapsed = !row.collapsed;
3403 newCurrentRow = row;
3405 if(style.multiSelect)
3407 // Deselect everything if user didn't clicked on a row
3411 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3412 selRow.selectedFlag = unselected;
3414 //this.clickedRowIndex = rowIndex;
3416 else if(style.moveRows && !(mods.shift) &&
3417 (row.selectedFlag == selected || row.selectedFlag == tempSelected) &&
3418 !right && !(mods.isActivate))
3419 moveMultiple = true;
3425 if(row.selectedFlag == tempUnselected || row.selectedFlag == unselected)
3427 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3428 selRow.selectedFlag = unselected;
3429 row.selectedFlag = selected;
3432 //this.clickedRowIndex = rowIndex;
3438 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3439 selRow.selectedFlag = unselected;
3443 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3445 if(selRow != clickedRow)
3447 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3448 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3455 if(rowIndex >= clickedRow.index)
3457 for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
3461 if(selRow != clickedRow)
3463 if(selRow.selectedFlag)
3464 selRow.selectedFlag = tempUnselected;
3466 selRow.selectedFlag = tempSelected;
3470 selRow.selectedFlag = selected;
3477 for(selRow = row; selRow; selRow = selRow.GetNextRow())
3481 if(selRow != clickedRow)
3483 if(selRow.selectedFlag)
3484 selRow.selectedFlag = tempUnselected;
3486 selRow.selectedFlag = tempSelected;
3490 selRow.selectedFlag = selected;
3491 if(selRow == clickedRow)
3500 if(row.selectedFlag)
3501 row.selectedFlag = tempUnselected;
3502 else row.selectedFlag = tempSelected;
3505 row.selectedFlag = tempSelected;
3507 //this.clickedRowIndex = rowIndex;
3517 // true: destroy edit box
3520 incref newCurrentRow;
3523 if(currentRow != newCurrentRow)
3524 HideEditBox(true, true, false);
3528 if(newCurrentRow._refCount <= 1)
3529 delete newCurrentRow;
3531 newCurrentRow._refCount--;
3536 if(!(style.multiSelect))
3538 if(currentRow) currentRow.selectedFlag = unselected;
3539 if(newCurrentRow) newCurrentRow.selectedFlag = selected;
3543 if(currentRow != newCurrentRow)
3546 // true: destroy edit box
3549 //incref newCurrentRow;
3550 incref newCurrentRow;
3553 HideEditBox(true, true, false);
3558 int headerSize = ((style.header) ? rowHeight : 0);
3559 int height = clientSize.h + 1 - headerSize;
3561 /*if(newCurrentRow._refCount <= 1)
3562 delete newCurrentRow;
3565 newCurrentRow._refCount--;
3566 //newCurrentRow._refCount--;
3569 currentRow = newCurrentRow;
3571 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
3572 SetScrollPosition(scroll.x,
3573 currentRow.index * rowHeight - height + rowHeight);
3574 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
3576 int line = currentRow ? currentRow.index * rowHeight : 0;
3577 //SNAPUP(line, rowHeight);
3578 SetScrollPosition(scroll.x, line);
3581 // GO THROUGH SetCurrentRow eventually?
3582 // SetCurrentRow(newCurrentRow, true);
3586 if(style.freeSelect)
3587 NotifyHighlight(master, this, currentRow, mods);
3588 else if((moveMultiple || (!(style.multiSelect) && previousRow == currentRow)) &&
3589 newCurrentRow && !(mods.shift))
3593 if(!(mods.isActivate))
3597 this.dragRow = currentRow;
3598 this.dropIndex = -1;
3599 this.movedRow = false;
3601 if(editData && editData.visible && style.alwaysEdit)
3608 if(style.collapse && !style.treeBranch)
3611 for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3613 indent += (style.treeBranch) ? 20 : 15;
3616 for(field = fields.first; field; field = field.next)
3618 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3619 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3621 if(!field.prev) width -= indent;
3622 if(x >= sx && x < sx + width)
3626 if(field == currentField)
3627 editData.Deactivate();
3630 currentRow.Edit(field);
3631 editData.Activate();
3634 else if(!(mods.ctrl) && numSelected <= 1)
3635 this.editRow = currentRow;
3637 if(style.noDragging && newCurrentRow)
3638 NotifyReclick(master, this, newCurrentRow, mods);
3642 // If the user clicked exactly on the edited field,
3644 if(editData && editData.visible && newCurrentRow)
3646 DataField field, whichField;
3650 if(style.collapse && !(style.treeBranch))
3653 whichField = currentField;
3657 for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3659 indent += (style.treeBranch) ? 20 : 15;
3663 for(field = fields.first; field; field = field.next)
3665 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3666 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3667 if(!field.prev) width -= indent;
3668 if(x >= sx && x < sx + width && newCurrentRow)
3673 if(field) //x >= sx && x < sx + width && newCurrentRow)
3675 if(field == currentField)
3676 editData.Activate();
3678 newCurrentRow.Edit(currentField);*/
3680 else if(style.noDragging && newCurrentRow)
3681 NotifyReclick(master, this, newCurrentRow, mods);
3683 else if(style.noDragging && newCurrentRow)
3684 NotifyReclick(master, this, newCurrentRow, mods);
3690 result = NotifySelect(master, this,
3691 currentRow ? currentRow : null, mods);
3692 if(result && style.alwaysEdit && currentRow)
3696 DataField field = null;
3701 if(style.collapse && !style.treeBranch)
3704 for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3706 indent += (style.treeBranch) ? 20 : 15;
3709 for(field = fields.first; field; field = field.next)
3711 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3712 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3714 if(!field.prev) width -= indent;
3715 if(x >= sx && x < sx + width)
3717 currentField = field;
3723 currentRow.Edit(currentField);
3725 // If the user clicked exactly on the edited field,
3727 if(editData && editData.visible && newCurrentRow)
3731 editData.Activate();
3733 else if(style.noDragging && newCurrentRow)
3734 NotifyReclick(master, this, newCurrentRow, mods);
3737 else if(style.noDragging && newCurrentRow)
3738 NotifyReclick(master, this, newCurrentRow, mods);
3742 For drop box to capture...
3745 if(x < 0 || y < 0 || x >= clientSize.w || y >= clientSize.h)
3748 master.parent.Activate();
3757 if(!style.noDragging)
3759 this.dragging = true;
3762 if(x >= 0 && y >= 0 && x < clientSize.w && y < clientSize.h)
3763 this.rolledOver = true;
3768 this.dragging = false;
3769 OnLeftButtonUp(x, y, mods);
3774 bool OnLeftButtonDown(int x, int y, Modifiers mods)
3776 return OnButtonDown(x,y, mods, false);
3779 bool OnLeftButtonUp(int x, int y, Modifiers mods)
3781 if(resizingField && style.alwaysEdit)
3783 Window::FreeMouseRange();
3785 resizingField = null;
3788 if(dragRow || editRow)
3790 DataRow row, switchRow = rows.last;
3791 int rowY = (style.header) ? rowHeight : 0;
3792 for(row = firstRowShown; row; row = row.GetNextRow())
3801 if(this.editRow == switchRow && y >= 0)
3806 for(field = fields.first; field; field = field.next)
3808 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3809 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3812 if(fieldX > x + scroll.x)
3816 if(field && field.editable)
3818 // true: destroy edit box
3819 HideEditBox(true, true, false);
3820 PopupEditBox(field, false);
3822 else if(!style.noDragging)
3823 NotifyReclick(master, this, currentRow, mods);
3825 else if(style.moveRows && switchRow)
3827 if(this.dragRow == switchRow && this.movedRow == false)
3829 DataRow row = this.dragRow;
3833 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3834 selRow.selectedFlag = unselected;
3838 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3840 if(selRow != clickedRow)
3842 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3843 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3849 if(row.selectedFlag)
3850 row.selectedFlag = tempUnselected;
3851 else row.selectedFlag = tempSelected;
3854 row.selectedFlag = tempSelected;
3859 if(style.multiSelect)
3861 if(!switchRow.selectedFlag)
3863 bool foundSwitch = false;
3866 DataRow afterRow = switchRow.prev;
3867 for(row = rows.first; row; row = next)
3869 next = row.GetNextRow();
3870 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
3872 if(!foundSwitch && !after)
3875 afterRow = switchRow;
3877 if(!after || !(row.selectedFlag == selected || row.selectedFlag == tempSelected) ||
3884 else if(row == switchRow)
3891 for(row = rows.first; row; row = row.GetNextRow())
3893 if(row == switchRow || row == this.dragRow)
3897 // Switch row first: move before
3898 if(row == switchRow)
3900 if(NotifyMove(master, this, switchRow.prev, mods))
3901 dragRow.Move(switchRow.prev);
3903 // Dragged row first: move after
3906 if(NotifyMove(master, this, switchRow, mods))
3907 dragRow.Move(switchRow);
3920 if(this.dragging || style.freeSelect)
3924 this.rolledOver = this.dragging = false;
3926 if(x >= 0 && y >= 0 && x < clientSize.w && y < clientSize.h && currentRow && style.freeSelect)
3930 result = NotifySelect(master, this, currentRow, mods);
3931 if(style.alwaysEdit)
3932 currentRow.Edit(currentField);
3936 // if(!(style.freeSelect))
3942 bool OnLeftDoubleClick(int x, int y, Modifiers mods)
3944 int rowStart = -scroll.x;
3946 int rowY = (style.header) ? rowHeight : 0;
3949 OnLeftButtonUp(x,y,mods);
3950 if(style.alwaysEdit)
3952 if(!(style.collapse) || x > 15)
3953 if(editData && editData.visible)
3955 editData.Activate();
3956 NotifyDoubleClick(master, this, x, y, mods);
3960 for(row = firstRowShown; row; row = row.GetNextRow())
3963 if(rowY > y || (style.multiSelect && !row.GetNextRow()))
3965 if(style.treeBranch)
3968 for(parent = (style.rootCollapse) ? row.parent : (row.parent ? row.parent.parent : null); parent; parent = parent.parent)
3977 if((row && style.collapse && (x >= rowStart && x <= rowStart + 18 + plusIndent)) ||
3978 NotifyDoubleClick(master, this, x, y, mods))
3982 if(row && row.subRows.first)
3984 row.collapsed = !row.collapsed;
3988 // We need to return true here so that OnLeftButtonDown can popup the DataBox Editors
3994 bool OnRightButtonDown(int x, int y, Modifiers mods)
3996 return OnButtonDown(x,y, mods, true);
3999 bool OnRightButtonUp(int x, int y, Modifiers mods)
4001 OnLeftButtonUp(x,y,mods);
4002 return NotifyRightClick(master, this, x, y, mods);
4005 bool GoToLetter(unichar ch, bool keyHit)
4007 bool result = false;
4009 bool checkNextField = true;
4010 int len = keyHit ? 0 : strlen(typedString);
4012 typedString = renew typedString char[len + 2];
4013 typedString[len++] = (char)tolower(ch); // TODO: FIX UNICODE
4014 typedString[len] = '\0';
4016 for(field = fields.first; field; field = field.next)
4018 DataRow startRow = currentRow ? currentRow : rows.first;
4020 if(startRow && field.dataType && field.dataType._vTbl[__ecereVMethodID_class_OnGetString] && ch)
4023 bool looped = false;
4024 if(len == 1 && currentRow)
4025 startRow = (next = startRow.GetNextRow(), (next ? next : rows.first));
4027 for(row = startRow; row != startRow || !looped; next = row.GetNextRow(), row = next ? next : rows.first)
4029 void * data = row.GetData(field);
4030 char tempString[1024] = "";
4031 bool needClass = false;
4032 char * string = data ? (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass) : null;
4034 if(string && string[0])
4035 checkNextField = false;
4036 if(string && string[0] && !strnicmp(string, typedString, len))
4038 if(style.multiSelect)
4041 bool foundRow = false;
4043 //this.clickedRowIndex = 0;
4045 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4047 if(selRow == row) foundRow = true;
4048 selRow.selectedFlag = unselected;
4049 //if(!foundRow) this.clickedRowIndex++;
4051 row.selectedFlag = selected;
4053 SetCurrentRow(row, true);
4060 if(this.typingTimeOut && !keyHit)
4061 typingTimer.Start();
4062 if(!result || !this.typingTimeOut || keyHit)
4063 typedString[len-1] = '\0';
4065 if(!checkNextField || result) break;
4070 bool OnKeyDown(Key key, unichar ch)
4074 if(key == enter || key == keyPadEnter)
4076 if(editData && editData.visible && editData.active)
4078 HideEditBox(true, false, false);
4082 else if(key == escape)
4084 if(resizingField || this.movingFields || (editData && editData.visible) || this.dragRow)
4086 if(editData && editData.visible && style.alwaysEdit && !editData.active)
4088 // false: dont destroy edit box
4089 HideEditBox(false, false, false);
4092 resizingField.width = this.startWidth;
4093 AdaptToFieldWidth(resizingField, true);
4094 resizingField = null;
4097 this.dragRow = null;
4100 this.dragging = false;
4104 this.movingFields = false;
4105 draggingField = null;
4111 if(!currentField || !currentField.editable)
4112 for(field = fields.first; field; field = field.next)
4116 currentField = field;
4120 if(key == f2 && currentField && currentField.editable)
4122 PopupEditBox(currentField, false);
4123 if(editData && editData.visible)
4125 if(style.alwaysEdit)
4126 editData.Activate();
4131 if(!NotifyKeyDown(master, this, currentRow, key, ch))
4134 // Editable fields...
4137 if(style.alwaysEdit && editData && editData.visible)
4138 return editData.OnKeyDown(key, ch);
4139 return true; // We want to pick up the OnKeyHit to replace contents, but skip GoToLetter
4142 if(ch != 128 && !key.alt && !key.ctrl && GoToLetter(ch, false))
4144 /*if(inactive && window.state != Hidden)
4145 NotifyHighlight(master, this, currentRow, 0);
4148 NotifySelect(master, this, currentRow, 0);
4155 bool OnKeyHit(Key key, unichar ch)
4157 if(!ch && !key.alt && !key.ctrl)
4159 key.code = (SmartKey)key.code;
4161 if(ch >= 32 && !key.alt && !key.ctrl && ch != 128)
4164 if(!currentField || !currentField.editable)
4165 for(field = fields.first; field; field = field.next)
4169 currentField = field;
4173 if(currentField && currentField.editable)
4175 if((!editData || !editData.visible) || !editData.active)
4177 PopupEditBox(currentField, false);
4178 if(editData && editData.visible)
4180 editData.Activate();
4181 editData.OnKeyHit(key, ch);
4188 if(editData && editData.visible && ch && !key.alt && !key.ctrl && editData.active)
4191 if(!key.alt && (style.multiSelect || !key.ctrl))
4196 if(style.alwaysEdit)
4201 for(field = currentField.prev; field; field = field.prev)
4205 currentField = field;
4206 HideEditBox(true, true, false);
4207 PopupEditBox(currentField, false);
4213 if(style.collapse && currentRow /*&& !currentField*/) // THIS PREVENTED COLLAPSING THE PROPERTY SHEET
4215 if(currentRow.subRows.first && !currentRow.collapsed)
4217 currentRow.collapsed = true;
4219 else if(currentRow.parent)
4220 SetCurrentRow(currentRow.parent, true);
4225 if(style.collapse && currentRow && currentRow.subRows.first)
4227 if(currentRow.collapsed)
4228 currentRow.collapsed = false;
4230 SetCurrentRow(currentRow.subRows.first, true);
4233 else if(style.alwaysEdit)
4238 for(field = currentField.next; field; field = field.next)
4242 currentField = field;
4243 HideEditBox(true, true, false);
4244 PopupEditBox(currentField, false);
4252 case pageDown: case pageUp:
4253 case end: case home:
4255 int headerSize = ((style.header) ? rowHeight : 0);
4256 int height = clientSize.h + 1 - headerSize;
4259 // true: destroy edit box
4260 // !!! TESTING true HERE !!!
4261 HideEditBox(true, true, false);
4262 // HideEditBox(false, true, false);
4264 oldRow = currentRow;
4266 SNAPDOWN(height, rowHeight);
4267 if((!currentRow || key.code == home) && key.code != end)
4269 currentRow = rows.first;
4277 if(!(style.multiSelect) && currentRow && !currentRow.selectedFlag)
4280 next = currentRow.GetNextRow();
4287 if(!(style.multiSelect) && currentRow && !currentRow.selectedFlag)
4290 next = currentRow.GetPrevRow();
4298 currentRow = lastRow.GetLastRow();
4304 currentRow && (next = currentRow.GetPrevRow()) && c < height / rowHeight;
4305 c++, currentRow = next);
4312 currentRow && (next = currentRow.GetNextRow()) && c < height / rowHeight;
4313 c++, currentRow = next);
4318 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
4319 SetScrollPosition(scroll.x, currentRow.index * rowHeight - height + rowHeight);
4320 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
4321 SetScrollPosition(scroll.x, currentRow ? currentRow.index * rowHeight : 0);
4323 if(style.multiSelect)
4327 if(!(key.shift) && (key.ctrl))
4330 for(row = rows.first; row; row = row.GetNextRow())
4332 if(row.selectedFlag == tempSelected)
4333 row.selectedFlag = selected;
4334 else if(row.selectedFlag == tempUnselected)
4335 row.selectedFlag = unselected;
4341 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4342 selRow.selectedFlag = unselected;
4346 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4348 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
4349 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
4355 if(currentRow.index >= clickedRow.index)
4357 for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
4361 if(selRow.selectedFlag) selRow.selectedFlag = tempUnselected; else selRow.selectedFlag = tempSelected;
4364 selRow.selectedFlag = selected;
4365 if(selRow == currentRow)
4371 for(selRow = currentRow; selRow; selRow = selRow.GetNextRow())
4375 if(selRow.selectedFlag) selRow.selectedFlag = tempUnselected; else selRow.selectedFlag = tempSelected;
4378 selRow.selectedFlag = selected;
4379 if(selRow == clickedRow)
4386 if(!(key.ctrl) && currentRow)
4388 currentRow.selectedFlag = selected;
4391 clickedRow = currentRow;
4396 if(oldRow) oldRow.selectedFlag = unselected;
4397 if(currentRow) currentRow.selectedFlag = selected;
4402 if(style.freeSelect)
4403 NotifyHighlight(master, this, currentRow, 0);
4405 NotifySelect(master, this, currentRow, 0);
4407 if(style.alwaysEdit && currentRow)
4408 currentRow.Edit(currentField /*null*/);
4415 if(style.multiSelect && currentRow)
4417 if(currentRow.selectedFlag)
4420 currentRow.selectedFlag = unselected;
4423 currentRow.selectedFlag = selected;
4426 if(style.freeSelect)
4427 NotifyHighlight(master, this, currentRow, 0);
4429 NotifySelect(master, this, currentRow, 0);
4436 if(!NotifyKeyHit(master, this, currentRow, key, ch))
4439 if(ch != 128 && !key.alt && !key.ctrl && GoToLetter(ch, true))
4441 /*if(inactive && window.state != Hidden)
4442 return NotifyHighlight(master, this, currentRow, 0);
4445 return NotifySelect(master, this, currentRow, 0);
4452 void OnHScroll(ScrollBarAction action, int position, Key key)
4457 void OnVScroll(ScrollBarAction action, int position, Key key)
4462 for(firstRowShown = rows.first; firstRowShown; firstRowShown = next)
4464 next = firstRowShown.GetNextRow();
4465 if(y >= position || !next) break;
4475 DataRow firstRowShown;
4479 DataField sortField;
4483 double typingTimeOut;
4496 if(guiApp.GetKeyState(shift)) mods.shift = true;
4497 if(guiApp.GetKeyState(alt)) mods.alt = true;
4498 if(guiApp.GetKeyState(control)) mods.ctrl = true;
4499 OnMouseMove(MAXINT, MAXINT, mods);
4507 delay = 0.5; // typingTimeOut
4512 typedString[0] = '\0';
4514 // The next line was commented... Why? When commented typing words stops working ( only first character jumps )
4520 bool dragging, rolledOver;
4529 // For editing fields
4531 DataField currentField;
4534 // For moving fields
4535 DataField draggingField, dropField;
4538 // For resizing fields
4539 DataField resizingField;
4540 int resizeX, oldX, startWidth;
4543 FontResource boldFont;
4546 // Only used for OnMouseMove so far, for avoiding problems with consequential mouse moves
4547 bool insideNotifySelect;
4548 Color selectionColor, selectionText, stippleColor;
4549 stippleColor = 0xFFFFFF80;