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;
173 for(row = listBox.firstRow; row; row = row.GetNextRow())
177 for(i = 0, cell = row.cells.first; i != index; i++, cell = cell.next);
178 if(cell && cell.isSet && dataType)
180 static char tempString[4096];
183 if(dataType.type == normalClass || dataType.type == noHeadClass)
184 string = (char *)dataType._vTbl[__ecereVMethodID_class_OnGetString](dataType, cell.data[0], tempString, userData, null);
186 string = (char *)dataType._vTbl[__ecereVMethodID_class_OnGetString](dataType, cell.data, tempString, userData, null);
188 display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, null);
190 display.FontExtent(row.header ? boldFont : font, "", 0, &tw, null);
191 if(tw > width) width = tw;
195 property::width = width;
202 // property::dataType = "String";
203 property::dataType = "char *";
215 headButton.Destroy(0);
220 listBox.fields.Remove(this);
221 for(field = listBox.fields.first; field; field = field.next)
223 if(field.index >= index)
226 if(listBox.currentField == this)
227 listBox.currentField = null;
229 listBox.OnResize(listBox.clientSize.w, listBox.clientSize.h);
234 DataField prev, next;
258 property int tag { set { tag = value; } get { return tag; } };
259 property DataRow previous { get { return prev; } };
260 property DataRow next { get { return next; } };
261 property int index { get { return (this && (!parent || parent.IsExpanded())) ? index : -1; } };
262 property char * string
264 set { SetData(listBox.fields.first, value); }
265 get { return GetData(listBox.fields.first); }
267 property bool isHeader { set { header = value; } get { return this ? header : false; } };
268 property BitmapResource icon { set { icon = value; } get { return icon; } };
269 property bool collapsed
273 if(collapsed != value)
276 if(parent.IsExpanded())
283 for(search = subRows.first; search; search = search.next)
284 search.selectedFlag = 0;
286 if(listBox.clickedRow && !listBox.clickedRow.parent.IsExpanded())
288 listBox.clickedRow = GetNextRow();
289 if(!listBox.clickedRow)
290 listBox.clickedRow = this;
292 if(listBox.currentRow && !listBox.currentRow.parent.IsExpanded())
294 listBox.SetCurrentRow(this, true);
296 if(listBox.firstRowShown && !listBox.firstRowShown.parent.IsExpanded())
298 listBox.firstRowShown = GetPrevRow();
299 if(!listBox.firstRowShown)
300 listBox.firstRowShown = this;
304 index = this.index+1;
305 for(search = GetNextRow(); search; search = search.GetNextRow())
306 search.index = index++;
307 listBox.rowCount = index;
309 listBox.HideEditBox(false, false, true);
311 listBox.SetScrollArea(
313 (listBox.rowCount * listBox.rowHeight) +
314 ((listBox.style.header) ? listBox.rowHeight : 0) -
315 ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
316 listBox.Update(null);
317 listBox.NotifyCollapse(listBox.master, listBox, this, value);
322 listBox.CheckConsistency();
325 get { return this ? collapsed : false; }
327 property bool selected
333 selectedFlag = value ? selected : unselected;
334 listBox.Update(null);
337 get { return selectedFlag == selected || selectedFlag == tempSelected; }
339 property DataRow parent
343 if(this && (value != this))
346 DataRow after = value ? value.subRows.last : listBox.rows.last;
347 int ixCount = (!collapsed && subRows.count) ? GetLastRow().index - index + 1 : 1;
348 if(parent.IsExpanded())
350 for(search = GetNextRow(); search; search = search.GetNextRow())
351 search.index -= ixCount;
352 listBox.rowCount -= ixCount;
355 listBox.HideEditBox(false, false, true);
358 if(this == listBox.clickedRow)
360 listBox.clickedRow = GetNextRow();
361 if(!listBox.clickedRow)
362 listBox.clickedRow = GetPrevRow();
365 if(this == listBox.currentRow)
367 DataRow newCurrentRow = GetNextRow();
368 if(!listBox.newCurrentRow)
369 listBox.newCurrentRow = GetPrevRow();
370 listBox.SetCurrentRow(newCurrentRow, true);
373 if(this == listBox.firstRowShown)
375 listBox.firstRowShown = GetPrevRow();
376 if(!listBox.firstRowShown)
377 listBox.firstRowShown = GetNextRow();
381 (parent ? parent.subRows : listBox.rows).Remove(this);
384 value.subRows.Insert(after, this);
386 listBox.rows.Insert(after, this);
390 if(value && listBox.style.expandOnAdd)
393 value.skipCheck = true;
395 value.collapsed = false;
397 value.skipCheck = false;
401 if(value.IsExpanded(this))
405 if(after && after.subRows.first && !after.collapsed)
407 search = after.GetLastRow();
408 index = search.index + 1;
411 index = after ? (after.index + 1) : (index + 1);
413 listBox.rowCount += ixCount;
417 for(search = GetNextRow(); search; search = search.GetNextRow())
421 listBox.SetScrollArea(
423 (listBox.rowCount * listBox.rowHeight) +
424 ((listBox.style.header) ? listBox.rowHeight : 0) -
425 ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
426 if(listBox.style.autoScroll)
427 listBox.SetScrollPosition(0, MAXINT - listBox.rowHeight);
429 // TESTING THIS HERE...
431 listBox.Sort(listBox.sortField, listBox.sortField.sortOrder);
434 int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
435 int height = listBox.clientSize.h + 1 - headerSize;
436 if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
437 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
438 else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
440 int line = listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0;
441 listBox.SetScrollPosition(listBox.scroll.x, line);
444 listBox.OnVScroll(0, listBox.scroll.y, 0);
446 listBox.Update(null);
454 property DataRow lastRow { get { return this ? subRows.last : null; } };
455 property DataRow firstRow { get { return this ? subRows.first : null; } };
457 void Edit(DataField field)
463 if(!field || !field.editable)
465 for(field = listBox.fields.first; field; field = field.next)
466 if(field.editable) break;
468 if(field && field.editable)
470 listBox.SetCurrentRow(this, true);
471 listBox.PopupEditBox(field, false);
477 // NOTE: This does not support reparenting (Use row.parent = first)
478 void Move(DataRow after)
483 if(listBox && prev != after)
487 int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
488 int height = listBox.clientSize.h + 1 - headerSize;
489 int ixCount = (!collapsed && subRows.count) ? GetLastRow().index - index + 1 : 1;
491 if(!after || after.index < index)
493 if(after == listBox.firstRowShown.prev)
494 listBox.firstRowShown = this;
496 // All rows between AFTER (exclusive) and ROW (exclusive) are incremented by one
497 // ROW is equal to AFTER's index + 1
499 for(search = after ? after.next : listBox.rows.first; search && search != this; search = search.GetNextRow())
500 search.index += ixCount;
502 if(after && after.subRows.first && !after.collapsed)
504 search = after.GetLastRow();
505 index = search.index + 1;
508 index = after ? (after.index + 1) : 0;
510 // Fix indices of sub rows
514 for(c = 1, search = GetNextRow(); search && c < ixCount; c++, search = search.GetNextRow())
520 DataRow nextRow = GetNextRow();
521 if(this == listBox.firstRowShown)
523 listBox.firstRowShown = nextRow;
524 index = after ? (after.index + 1) : 0;
527 // All rows between ROW (exclusive) and AFTER (inclusive) are decremented by one
528 // ROW is equal to AFTER's index
530 for(search = nextRow; search; search = search.GetNextRow())
532 search.index -= ixCount;
533 if(search == after) break;
536 listBox.rows.Move(this, after);
539 listBox.CheckConsistency();
542 listBox.HideEditBox(true, false, true);
545 if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
546 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
547 else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
549 int line = listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0;
550 //SNAPUP(line, listBox.rowHeight);
551 listBox.SetScrollPosition(listBox.scroll.x, line);
554 listBox.OnVScroll(0, listBox.scroll.y, 0);
556 listBox.modifiedDocument = true;
558 listBox.Update(null);
565 any_object GetData(DataField field)
569 ListBoxCell cell = listBox.GetCell(&this, &field);
570 if(cell && cell.isSet && cell.data)
572 if((field.dataType.type == normalClass || field.dataType.type == noHeadClass))
575 return (void *)cell.data; // Cast for MemoryGuard
581 void * SetData(DataField field, any_object newData)
585 ListBoxCell cell = listBox.GetCell(&this, &field);
588 Class dataType = field.dataType;
592 if(dataType.type == normalClass || dataType.type == noHeadClass)
594 if(cell.data[0] && field.freeData)
595 dataType._vTbl[__ecereVMethodID_class_OnFree](dataType, cell.data[0]);
597 if(eClass_IsDerived(dataType, class(char *)) && field.freeData)
598 dataType._vTbl[__ecereVMethodID_class_OnCopy](dataType, cell.data, newData);
600 cell.data[0] = (void *)newData;
604 // Free old data first
605 dataType._vTbl[__ecereVMethodID_class_OnFree](dataType, cell.data);
606 dataType._vTbl[__ecereVMethodID_class_OnCopy](dataType, cell.data, newData);
610 listBox.modifiedDocument = true;
611 listBox.Update(null);
612 if(dataType && (dataType.type == normalClass || dataType.type == noHeadClass))
613 return (void *)cell.data; // Cast for MemoryGuard
621 void UnsetData(DataField field)
625 ListBoxCell cell = listBox.GetCell(&this, &field);
628 Class dataType = field.dataType;
632 if(dataType.type == normalClass || dataType.type == noHeadClass)
634 if(cell.data[0] && field.freeData)
635 dataType._vTbl[__ecereVMethodID_class_OnFree](dataType, cell.data[0]);
640 // Free old data first
641 dataType._vTbl[__ecereVMethodID_class_OnFree](dataType, cell.data);
645 listBox.Update(null);
650 DataRow FindRow(int tag)
653 for(row = subRows.first; row; row = row.next)
655 if(!row.noneRow && row.tag == tag)
661 DataRow FindSubRow(int tag)
664 for(row = subRows.first; row; row = row.next)
666 if(!row.noneRow && row.tag == tag)
668 if(row.subRows.first)
670 DataRow subRow = row.FindSubRow(tag);
678 DataRow AddRowAfter(DataRow after)
688 subRows.Insert(after, row);
689 row.listBox = listBox;
693 for(c = 0; c<listBox.fields.count; c++)
695 for(field = listBox.fields.first; field; field = field.next)
696 if((int)field.index == c)
700 int size = (field.dataType && field.dataType.typeSize) ?
701 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
702 ListBoxCell cell = (ListBoxCell)new0 byte[size];
704 FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
713 if(after && after.subRows.first && !after.collapsed)
715 for(search = after.subRows.last; !search.collapsed && search.subRows.last; )
716 search = search.subRows.last;
717 row.index = search.index + 1;
720 row.index = after ? (after.index + 1) : (index + 1);
724 for(search = row.GetNextRow(); search; search = search.GetNextRow())
727 listBox.SetScrollArea(
729 (listBox.rowCount * listBox.rowHeight) +
730 ((listBox.style.header) ? listBox.rowHeight : 0) -
731 ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
732 if(listBox.style.autoScroll)
733 listBox.SetScrollPosition(0, MAXINT - listBox.rowHeight);
736 listBox.modifiedDocument = true;
739 listBox.CheckConsistency();
749 return AddRowAfter(subRows.last);
753 DataRow AddStringf(char * format, ...)
758 char string[MAX_F_STRING];
761 va_start(args, format);
762 vsprintf(string, format, args);
766 row.SetData(null, string);
772 DataRow AddString(char * string)
778 row.SetData(listBox.fields.first, string);
788 subRows.offset = (uint)&((DataRow)0).prev;
793 ListBoxCell cell, next;
798 while((subRow = subRows.first))
800 subRows.Remove(subRow);
804 for(cell = cells.first; cell; cell = next, cellIndex++)
809 for(field = listBox.fields.first; field && field.index != cellIndex; field = field.next);
812 // TOCHECK: Is this check good? Will need incref/decref sometime?
813 if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
815 if(cell.data[0] && field.freeData)
816 field.dataType._vTbl[__ecereVMethodID_class_OnFree](field.dataType, cell.data[0]);
819 field.dataType._vTbl[__ecereVMethodID_class_OnFree](field.dataType, cell.data);
829 return !this || (!collapsed && (!parent || parent.IsExpanded()));
832 int Compare(DataRow b, DataField sortField)
835 ListBoxCell cell1, cell2;
837 for(index = 0, cell1 = cells.first, cell2 = b.cells.first;
838 index != sortField.index;
839 index++, cell1 = cell1.next, cell2 = cell2.next);
841 if(!cell1.isSet && !cell2.isSet)
843 else if(!cell1.isSet)
845 else if(!cell2.isSet)
848 if(noneRow && !b.noneRow) return -1;
849 else if(!noneRow && b.noneRow) return 1;
850 else if(noneRow && b.noneRow) return 0;
852 if(sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare])
854 if(sortField.dataType.type == normalClass || sortField.dataType.type == noHeadClass)
856 result = sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare](sortField.dataType,
857 (cell1.isSet && cell1.data) ? cell1.data[0] : null,
858 (cell2.isSet && cell2.data) ? cell2.data[0] : null);
862 result = sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare](sortField.dataType,
863 cell1.isSet ? cell1.data : null,
864 cell2.isSet ? cell2.data : null);
867 return sortField.sortOrder * result;
870 void _SortSubRows(DataField field, int order)
873 for(search = subRows.first; search; search = search.next)
874 search._SortSubRows(field, order);
875 subRows.Sort(Compare, field);
878 public void SortSubRows(bool scrollToCurrent)
880 if(this && listBox && listBox.sortField)
882 _SortSubRows(listBox.sortField, listBox.sortField.sortOrder);
886 int index = this.index;
887 for(search = this; search; search = search.GetNextRow())
888 search.index = index++;
892 int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
893 int height = listBox.clientSize.h + 1 - headerSize;
894 if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
895 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
896 else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
897 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0);
898 listBox.OnVScroll(0, listBox.scroll.y, 0);
903 public DataRow GetPrevRow()
909 for(row = prev; row && !row.collapsed && row.subRows.last; row = row.subRows.last);
916 public DataRow GetNextRow()
920 if(subRows.first && !collapsed)
924 for(row = this; row; row = row.parent)
926 if(row.next) { row = row.next; break; }
932 private DataRow GetLastRow()
935 while(row && !row.collapsed && row.subRows.last)
936 row = row.subRows.last;
943 SelectedFlag selectedFlag;
954 public class ListBox : CommonControl
956 hasVertScroll = true;
957 // background = white;
959 snapVertScroll = true;
961 class_property(icon) = "<:ecere>controls/listBox.png";
965 property bool freeSelect { property_category $"Behavior" set { style.freeSelect = value; } get { return style.freeSelect; } };
966 property DataRow currentRow { property_category $"Private" /*"Behavior"*/ set { SetCurrentRow(value, false); } get { return currentRow; } };
967 property DataField currentField
969 get { return currentField; }
970 // TODO: Document what this does
973 currentField = value;
974 HideEditBox(true, true, false);
975 if(value && value.editable)
976 PopupEditBox(currentField, false);
980 property int rowHeight
982 property_category $"Appearance"
983 isset { return style.heightSet; }
988 style.heightSet = true;
990 SetScrollLineStep(8, value);
994 style.heightSet = false;
999 get { return rowHeight; }
1001 property Seconds typingTimeout
1003 property_category $"Behavior"
1006 typedString[0] = '\0';
1007 typingTimer.delay = value;
1008 typingTimeOut = value;
1010 get { return typingTimeOut; }
1012 property bool moveRows { property_category $"Behavior" set { style.moveRows = value; } get { return style.moveRows; } };
1013 property bool moveFields { property_category $"Behavior" set { style.moveFields = value; } get { return style.moveFields; } };
1014 property bool resizable { property_category $"Behavior" set { style.resizable = value; } get { return style.resizable; } };
1015 property bool autoScroll { property_category $"Behavior" set { style.autoScroll = value; } get { return style.autoScroll; } };
1016 property bool alwaysHighLight { property_category $"Appearance" set { style.alwaysHL = value; } get { return style.alwaysHL; } };
1017 property bool hasClearHeader { property_category $"Appearance" set { style.clearHeader = value; if(value) property::hasHeader = true; } get { return style.clearHeader; } };
1018 property bool hasHeader
1020 property_category $"Appearance"
1023 if(value && !style.header)
1029 bevel = !guiApp.textMode && !style.clearHeader;
1030 dontScrollVert = true;
1033 NotifyPushed = HeaderPushed;
1034 NotifyClicked = HeaderClicked;
1035 NotifyDoubleClick = HeaderDoubleClicked;
1036 NotifyReleased = HeaderReleased;
1037 NotifyMouseMove = HeaderMouseMove;
1041 endBevel.visible = false;
1043 style.header = value;
1045 get { return style.header; }
1047 property bool multiSelect { property_category $"Behavior" set { style.multiSelect = value; } get { return style.multiSelect; } };
1048 property bool alwaysEdit { property_category $"Behavior" set { style.alwaysEdit = value; } get { return style.alwaysEdit; } };
1049 property bool fullRowSelect { property_category $"Appearance" set { style.fullRowSelect = value; } get { return style.fullRowSelect; } };
1050 property bool collapseControl { property_category $"Appearance" set { style.collapse = value; } get { return style.collapse; } };
1051 property bool treeBranches { property_category $"Appearance" set { style.treeBranch = value; } get { return style.treeBranch; } };
1052 property bool rootCollapseButton { property_category $"Appearance" set { style.rootCollapse = value; } get { return style.rootCollapse; } };
1053 property bool sortable { property_category $"Behavior" set { style.sortable = value; } get { return style.sortable; } };
1054 property bool noDragging { property_category $"Behavior" set { style.noDragging = value; } get { return style.noDragging; } };
1055 property bool fillLastField
1057 property_category $"Behavior"
1060 style.fillLastField = value;
1062 get { return style.fillLastField; }
1064 property int numSelections
1068 int numSelections = 0;
1069 if(this && style.multiSelect)
1072 for(row = rows.first; row; row = row.GetNextRow())
1073 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
1076 return numSelections;
1079 property int currentIndex
1081 get { return currentRow ? currentRow.index : -1; }
1083 property DataRow lastRow { get { return this ? rows.last : null; } };
1084 property DataRow firstRow { get { return this ? rows.first : null; } };
1085 property int rowCount { get { return rowCount; } };
1086 property DataField firstField { get { return this ? fields.first : null; } };
1087 property Color selectionColor { set { selectionColor = value; } get { return selectionColor; } isset { return selectionColor ? true : false; } };
1088 property Color selectionText { set { selectionText = value; } get { return selectionText; } isset { return selectionText ? true : false; } };
1089 property Color stippleColor { set { stippleColor = value; } get { return stippleColor; } };
1090 property bool expandOnAdd { set { style.expandOnAdd = value; } get { return style.expandOnAdd; } };
1093 virtual bool Window::NotifySelect(ListBox listBox, DataRow row, Modifiers mods);
1094 virtual bool Window::NotifyHighlight(ListBox listBox, DataRow row, Modifiers mods);
1095 virtual bool Window::NotifyReclick(ListBox listBox, DataRow row, Modifiers mods);
1096 virtual bool Window::NotifySort(ListBox listBox, DataField field, Modifiers mods);
1097 virtual bool Window::NotifyChanged(ListBox listBox, DataRow row);
1098 virtual bool Window::NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch);
1099 virtual bool Window::NotifyEdited(ListBox listBox, DataRow row);
1100 virtual bool Window::NotifyEditDone(ListBox listBox, DataRow row);
1101 virtual bool Window::NotifyMovedField(ListBox listBox, DataField field, Modifiers mods);
1102 virtual bool Window::NotifyMove(ListBox listBox, DataRow row, Modifiers mods);
1103 virtual bool Window::NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods);
1104 virtual bool Window::NotifyRightClick(ListBox listBox, int x, int y, Modifiers mods);
1105 virtual bool Window::NotifyResized(ListBox listBox, DataField field, Modifiers mods);
1106 virtual bool Window::NotifyCollapse(ListBox listBox, DataRow row, bool collapsed);
1107 virtual bool Window::NotifyKeyHit(ListBox listBox, DataRow row, Key key, unichar ch);
1108 virtual bool Window::NotifyModified(ListBox listBox, DataRow row);
1109 virtual bool Window::NotifyEditing(ListBox listBox, DataRow row);
1112 private void CheckConsistency()
1117 for(r = rows.first; r; r = r.GetNextRow())
1119 if(r.index != index++)
1127 void AddField(DataField addedField)
1132 if(fields.first && ((DataField)fields.first).defaultField)
1134 DataField defaultField = fields.first;
1135 defaultField.Free();
1136 delete defaultField;
1140 addedField = DataField { };
1144 addedField.listBox = this;
1145 fields.Add(addedField);
1147 addedField.sortOrder = 1;
1148 addedField.index = numFields;
1152 addedField.headButton.Destroy(0);
1153 delete addedField.headButton;
1154 addedField.headButton = Button
1159 dontScrollVert = true;
1160 id = (uint)addedField;
1161 text = addedField.header;
1162 bevel = (!guiApp.textMode && !style.clearHeader);
1164 alignment = addedField.alignment;
1165 NotifyPushed = HeaderPushed;
1166 NotifyClicked = HeaderClicked;
1167 NotifyDoubleClick = HeaderDoubleClicked;
1168 NotifyReleased = HeaderReleased;
1169 NotifyMouseMove = HeaderMouseMove;
1171 incref addedField.headButton;
1172 addedField.headButton.Create();
1175 addedField.headButton.background = Color { 0, 170, 0 };
1181 for(row = rows.first; row; )
1183 int size = (field.dataType && field.dataType.typeSize) ?
1184 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1185 ListBoxCell cell = (ListBoxCell)new0 byte[size];
1186 row.cells.Add(cell);
1187 FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
1190 if(row.subRows.first)
1191 row = row.subRows.first;
1194 for(; row; row = row.parent)
1196 if(row.next) { row = row.next; break; }
1201 OnResize(clientSize.w, clientSize.h);
1210 while((field = fields.first))
1216 endBevel.visible = false;
1221 void RemoveField(DataField field)
1227 int index = field.index;
1230 if(sortField == field)
1233 for(row = rows.first; row; )
1238 for(cell = row.cells.first, c = 0; c < index && cell; c++, cell = cell.next);
1239 if(cell && index == c)
1243 // TOCHECK: Is this check good? Will need incref/decref sometime?
1244 if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
1246 if(cell.data[0] && field.freeData)
1247 field.dataType._vTbl[__ecereVMethodID_class_OnFree](field.dataType, cell.data[0]);
1250 field.dataType._vTbl[__ecereVMethodID_class_OnFree](field.dataType, cell.data);
1253 row.cells.Remove(cell);
1257 if(row.subRows.first)
1258 row = row.subRows.first;
1261 for(; row; row = row.parent)
1263 if(row.next) { row = row.next; break; }
1272 endBevel.visible = false;
1276 DataRow AddRowNone()
1278 DataRow row { noneRow = true };
1287 rows.Insert(null, row);
1290 for(search = row.GetNextRow(); search; search = search.GetNextRow())
1296 firstRowShown = row;
1300 (rowCount * rowHeight) +
1301 ((style.header) ? rowHeight : 0) -
1302 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1303 if(style.autoScroll)
1304 SetScrollPosition(0, MAXINT - rowHeight);
1305 modifiedDocument = true;
1324 // Find very last row
1327 for(lastRow = rows.last; lastRow && !lastRow.collapsed && lastRow.subRows.last; lastRow)
1328 lastRow = lastRow.subRows.last;
1329 row.index = lastRow ? (lastRow.index + 1) : 0;
1337 for(c = 0; c<fields.count; c++)
1339 for(field = fields.first; field; field = field.next)
1340 if((int)field.index == c)
1344 int size = (field.dataType && field.dataType.typeSize) ?
1345 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1346 ListBoxCell cell = (ListBoxCell) new0 byte[size];
1347 row.cells.Add(cell);
1348 FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
1355 firstRowShown = row;
1361 (rowCount * rowHeight) +
1362 ((style.header) ? rowHeight : 0) -
1363 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1364 if(style.autoScroll)
1365 SetScrollPosition(0, MAXINT - rowHeight);
1366 modifiedDocument = true;
1377 DataRow AddRowAfter(DataRow after)
1389 if(after && after.subRows.first && !after.collapsed)
1391 for(search = after.subRows.last; !search.collapsed && search.subRows.last; )
1392 search = search.subRows.last;
1393 row.index = search.index + 1;
1396 row.index = after ? (after.index + 1) : 0;
1397 rows.Insert(after, row);
1400 for(search = row.GetNextRow(); search; search = search.GetNextRow())
1405 for(c = 0; c<fields.count; c++)
1407 for(field = fields.first; field; field = field.next)
1408 if((int)field.index == c)
1412 int size = (field.dataType && field.dataType.typeSize) ?
1413 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1414 ListBoxCell cell = (ListBoxCell) new0 byte[size];
1415 row.cells.Add(cell);
1416 FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
1420 if(!firstRowShown || !after)
1422 firstRowShown = row;
1427 (rowCount * rowHeight) +
1428 ((style.header) ? rowHeight : 0) -
1429 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1430 if(style.autoScroll)
1431 SetScrollPosition(0, MAXINT - rowHeight);
1432 modifiedDocument = true;
1442 DataRow AddStringf(char * format, ...)
1448 char string[MAX_F_STRING];
1451 va_start(args, format);
1452 vsprintf(string, format ? format : "", args);
1456 row.SetData(fields.first, string);
1462 DataRow AddString(char * string)
1468 row.SetData(fields.first, string);
1474 void SelectRow(DataRow row)
1476 SetCurrentRow(row, true);
1479 void DeleteRow(DataRow row)
1481 if(!row) row = currentRow;
1484 DataRow sub, next, search;
1485 // Trying to move this here (Messed up deleting watches)
1486 //HideEditBox(false, false, true);
1489 for(sub = row.subRows.first; sub; sub = next)
1495 if(row.parent.IsExpanded())
1497 for(search = row.GetNextRow(); search; search = search.GetNextRow())
1502 HideEditBox(false, false, true);
1504 if(row == clickedRow)
1506 clickedRow = row.GetNextRow();
1508 clickedRow = row.GetPrevRow();
1511 if(row == currentRow)
1513 DataRow newCurrentRow = row.GetNextRow();
1515 newCurrentRow = row.GetPrevRow();
1516 SetCurrentRow(newCurrentRow, true);
1519 if(row == firstRowShown)
1521 firstRowShown = row.GetPrevRow();
1523 firstRowShown = row.GetNextRow();
1526 (row.parent ? row.parent.subRows: rows).Remove(row);
1529 //HideEditBox(false, false, true);
1533 (this.rowCount * rowHeight) +
1534 ((style.header) ? rowHeight : 0) -
1535 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1537 modifiedDocument = true;
1546 DataRow FindRow(int tag)
1551 for(row = rows.first; row; row = row.next)
1553 if(!row.noneRow && row.tag == tag)
1561 DataRow FindString(char * searchedString)
1564 bool checkNextField = true;
1565 int len = searchedString ? strlen(searchedString) : 0;
1567 for(field = fields.first; field; field = field.next)
1569 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1572 for(row = rows.first; row; row = row.GetNextRow())
1576 void * data = row.GetData(field);
1577 char tempString[1024] = "";
1578 bool needClass = false;
1579 char * string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass);
1581 if(string && string[0])
1582 checkNextField = false;
1583 if(string && string[0] && !strcmp(string, searchedString))
1588 if(!checkNextField) break;
1593 DataRow FindSubString(char * subString)
1596 bool checkNextField = true;
1597 int len = subString ? strlen(subString) : 0;
1601 for(field = fields.first; field; field = field.next)
1603 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1606 for(row = rows.first; row; row = row.GetNextRow())
1610 void * data = row.GetData(field);
1611 char tempString[1024] = "";
1612 bool needClass = false;
1613 char * string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass);
1615 if(string && string[0])
1616 checkNextField = false;
1617 if(string && string[0] && !strncmp(string, subString, len))
1622 if(!checkNextField) break;
1628 DataRow FindSubStringi(char * subString)
1631 bool checkNextField = true;
1632 int len = subString ? strlen(subString) : 0;
1633 DataRow result = null;
1634 char * bestResult = null;
1639 for(field = fields.first; field; field = field.next)
1641 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1644 for(row = rows.first; row; row = row.GetNextRow())
1648 void * data = row.GetData(field);
1649 char tempString[1024] = "";
1650 bool needClass = false;
1651 char * string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass);
1653 if(string && string[0])
1654 checkNextField = false;
1655 if(string && string[0])
1657 int stringLen = strlen(string);
1659 if(!strnicmp(string, subString, Min(len, stringLen)))
1661 if(bestLen < Min(len, stringLen))
1663 if(!bestResult || strcmpi(string, bestResult) < 0)
1665 bestLen = Min(len, stringLen);
1666 bestResult = string;
1674 if(!checkNextField) break;
1680 DataRow FindSubStringAfter(DataRow after, char * subString)
1683 bool checkNextField = true;
1684 int len = subString ? strlen(subString) : 0;
1688 for(field = fields.first; field; field = field.next)
1690 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1693 for(row = after.GetNextRow(); row && row != after; row = row.GetNextRow(), (!row) ? (row = rows.first) : null)
1697 void * data = row.GetData(field);
1698 char tempString[1024] = "";
1699 bool needClass = false;
1700 char * string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass);
1702 if(string && string[0])
1703 checkNextField = false;
1704 if(string && string[0] && !strncmp(string, subString, len))
1709 if(!checkNextField) break;
1715 DataRow FindSubRow(int tag)
1721 for(row = rows.first; row; row = row.next)
1723 if(!row.noneRow && row.tag == tag)
1725 if(!row.noneRow && row.subRows.first)
1727 DataRow subRow = row.FindSubRow(tag);
1741 Window master = this.master;
1743 HideEditBox(false, true, false);
1744 editData.Destroy(0);
1746 firstRowShown = currentRow = null;
1751 if(style.freeSelect)
1752 NotifyHighlight(master, this, currentRow ? currentRow : null, 0);
1754 NotifySelect(master, this, currentRow ? currentRow : null, 0);
1757 if(style.alwaysEdit && currentRow)
1758 currentRow.Edit(currentField);
1765 (this.rowCount * rowHeight) +
1766 ((style.header) ? rowHeight : 0) -
1767 ((rowHeight && !((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1772 void Sort(DataField field, int order)
1777 int headerSize = ((style.header) ? rowHeight : 0);
1778 int height = clientSize.h + 1 - headerSize;
1780 if(!field) field = fields.first;
1782 field.sortOrder = order ? order : 1;
1783 rows.Sort(DataRow::Compare, field);
1785 for(search = rows.first; search; search = search.next)
1786 search._SortSubRows(field, order);
1790 for(search = rows.first; search; search = search.GetNextRow())
1791 search.index = index++;
1794 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
1795 SetScrollPosition(scroll.x, currentRow.index * rowHeight - height + rowHeight);
1796 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
1797 SetScrollPosition(scroll.x, currentRow ? currentRow.index * rowHeight : 0);
1799 OnVScroll(0, scroll.y, 0);
1801 // SetScrollPosition(0, scroll.y);
1806 void StopEditing(bool save)
1808 HideEditBox(save, false, true);
1811 void GetMultiSelection(OldList list)
1814 if(this && style.multiSelect)
1818 for(row = rows.first; row; row = row.GetNextRow())
1820 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
1822 list.Add(OldLink { data = row });
1828 // Convenience Current Row Methods
1829 void * SetData(DataField field, any_object data)
1831 return currentRow.SetData(field, data);
1834 any_object GetData(DataField field)
1836 return (void *)currentRow.GetData(field);
1841 return currentRow ? currentRow.tag : 0;
1847 DataField defaultField { };
1848 rows.offset = (uint)&((DataRow)0).prev;
1849 fields.offset = (uint)&((DataField)0).prev;
1850 style.fullRowSelect = true;
1851 style.fillLastField = true;
1852 style.expandOnAdd = true;
1853 typingTimeOut = 0.5;
1854 rowHeight = 16; // Stuff depending on creation and default property checking
1857 defaultField.defaultField = true;
1859 AddField(defaultField);
1861 typedString = new char[1];
1862 typedString[0] = '\0';
1877 while((field = fields.first))
1879 // fields.Remove(field);
1889 while((row = rows.first))
1896 ListBoxCell GetCell(DataRow * row, DataField * field)
1898 ListBoxCell cell = null;
1899 if(!*row) *row = currentRow;
1902 if(!*field) *field = this ? currentField : null;
1905 for(*field = fields.first; (*field).index != 0; *field = (*field).next);
1910 if(field->listBox == this)
1912 for(index = 0, cell = (*row).cells.first; cell && index != (*field).index; index++, cell = cell.next);
1919 void HideEditBox(bool save, bool alwaysStopEdit, bool repositionOnly)
1921 if(editData && editData.visible)
1923 Class dataType = currentField.dataType;
1925 editData.SaveData();
1927 editData.visible = false;
1928 NotifyEditDone(master, this, currentRow);
1930 // ENSURE DATA BOX IS NOT VISIBLE
1931 editData.visible = false;
1933 if(style.alwaysEdit && !alwaysStopEdit)
1936 int height = rowHeight - (style.alwaysEdit ? 1 : 0);
1937 int y = currentRow.index * rowHeight + (style.header ? rowHeight : 0);
1938 int x = currentField.x;
1939 int width = (!currentField.next && style.fillLastField && (!hasHorzScroll || clientSize.w - currentField.x > currentField.width + EXTRA_SPACE)) ?
1940 clientSize.w - currentField.x : (currentField.width + EXTRA_SPACE);
1942 if(!style.alwaysEdit)
1944 editData.position = { x, y };
1945 editData.size = { width, height };
1949 editData.position = { x, y - editData.clientStart.y };
1950 editData.size = { width, height + editData.clientStart.y * 2 };
1952 editData.visible = true;
1953 if(style.alwaysEdit)
1954 editData.Deactivate();
1956 PopupEditBox(currentField, repositionOnly);
1962 currentField = null;*/
1966 void SetCurrentRow(DataRow row, bool notify)
1968 if(currentRow != row || (currentRow && currentRow.selectedFlag == unselected))
1970 int headerSize = ((style.header) ? rowHeight : 0);
1971 int height = clientSize.h + 1 - headerSize;
1973 // true: destroy edit box
1974 HideEditBox(true, true, false);
1976 if(!(style.multiSelect) && currentRow)
1977 currentRow.selectedFlag = unselected;
1981 if(style.multiSelect)
1985 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
1986 selRow.selectedFlag = unselected;
1988 currentRow.selectedFlag = selected;
1993 currentRow.selectedFlag = selected;
1995 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
1996 SetScrollPosition(scroll.x,
1997 currentRow.index * rowHeight - height + rowHeight);
1998 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
2000 int line = currentRow ? currentRow.index * rowHeight : 0;
2001 //SNAPUP(line, rowHeight);
2002 SetScrollPosition(scroll.x, line);
2007 Window master = this.master;
2010 if(style.freeSelect && visible)
2011 NotifyHighlight(master, this, currentRow ? currentRow : null, 0);
2013 NotifySelect(master, this, currentRow ? currentRow : null, 0);
2014 if(style.alwaysEdit && currentRow)
2015 currentRow.Edit(currentField);
2023 void PopupEditBox(DataField whichField, bool repositionOnly)
2025 if((!editData || !editData.visible || currentField != whichField) && currentRow)
2027 // true: destroy edit box
2028 HideEditBox(true, true, false);
2031 int height = rowHeight - (style.alwaysEdit ? 1 : 0);
2033 int y = currentRow.index * rowHeight + (style.header ? rowHeight : 0);
2035 //void * data = currentRow.GetData(whichField);
2040 if(style.collapse && !(style.treeBranch))
2043 for(field = fields.first; field; field = field.next)
2045 width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2046 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2047 if(field == whichField) break;
2051 currentField = whichField;
2052 cell = GetCell(&row, ¤tField);
2059 background = dataBoxBackground;
2060 foreground = dataBoxForeground;
2062 bool NotifyChanged(bool closingDropDown)
2065 DataField field = null;
2066 ListBoxCell cell = GetCell(&row, &field);
2070 modifiedDocument = true;
2072 NotifyChanged(master, this, currentRow);
2077 bool NotifyModified()
2079 //DataRow row = null;
2080 //DataField field = null;
2081 //ListBoxCell cell = GetCell(&row, &field);
2082 //cell.isSet = true;
2083 modifiedDocument = true;
2085 NotifyModified(master, this, currentRow);
2089 bool OnKeyDown(Key key, unichar ch)
2091 bool result = DataBox::OnKeyDown(key, ch);
2092 if(visible && active) // Added this check here, because we will not use enter/escape otherwise, and lose DataBox's result
2094 if((SmartKey)key == enter || (SmartKey)key == escape)
2103 editData.Destroy(0);
2104 editData.type = whichField.dataType;
2105 editData.fieldData = whichField.userData;
2106 editData.borderStyle = style.alwaysEdit ? 0 : deep;
2107 editData.data = cell ? cell.data : null;
2110 // Might not really need this anymore...
2111 NotifyEditing(master, this, currentRow);
2114 if(!style.alwaysEdit)
2116 editData.position = { x, y - editData.clientStart.y };
2117 editData.size = { width, height + editData.clientStart.y * 2 };
2121 editData.position = { x, y };
2122 editData.size = { width, height };
2126 editData.visible = true;
2128 if(style.alwaysEdit)
2129 editData.Deactivate();
2131 // MOVED THIS HIGHER FOR DATALIST EDITOR
2133 // Might not really need this anymore...
2134 NotifyEdited(master, this, currentRow);
2139 void OnRedraw(Surface surface)
2142 int y = (style.header) ? rowHeight : 0;
2143 bool isActive = active;
2144 Font font = fontObject;
2145 Font boldFont = this.boldFont.font;
2149 if(style.alwaysEdit && style.fullRowSelect)
2152 int y = (style.header) ? rowHeight : 0;
2153 int x = -scroll.x - 1;// + EXTRA_SPACE;// / 2 - 1;
2154 int w = clientSize.w;
2155 int h = clientSize.h;
2159 // Fill out indent column
2160 if(style.collapse && !(style.treeBranch) && rows.first)
2163 surface.SetBackground(formColor);
2164 surface.Area(-scroll.x, 0, x, clientSize.h);
2167 surface.SetForeground(formColor);
2168 for(row = firstRowShown; row; row = row.GetNextRow())
2171 surface.HLine(x + 1, w-1, y-1);
2177 for(field = fields.first; field; field = field.next)
2179 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2180 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2181 if(field.prev && y > 0)
2182 surface.VLine(0, y-1, x);
2187 surface.foreground = this.foreground;
2188 surface.TextOpacity(false);
2190 // Draw the tree branches
2191 if(style.treeBranch)
2193 int y = -scroll.y + ((style.header) ? rowHeight : 0);
2194 surface.LineStipple(0x5555);
2195 surface.SetForeground(branchesColor);
2196 for(row = rows.first; row; row = row.GetNextRow() )
2198 int x = -scroll.x + EXTRA_SPACE / 2-1;
2199 int rowStart = -scroll.x;
2204 for(parent = row.parent; parent; parent = parent.parent)
2205 if(!parent.header) indent += 20;
2206 if(style.rootCollapse) indent += 20;
2208 plusIndent = (style.treeBranch) ? (indent - 20 + 4) : indent;
2213 if(row.subRows.first)
2216 int y1 = y + PLUSY + 4;
2220 for(child = row.collapsed ? null : row.subRows.first; child && child != row; )
2223 if(child.subRows.first && !child.collapsed && child != row.subRows.last)
2224 child = child.subRows.first;
2229 for(; child && child != row; child = child.parent)
2239 y2 = y + numRows * rowHeight + PLUSY + 4;
2240 surface.VLine(y1, y2, rowStart + plusIndent + 7 + 20);
2242 surface.HLine(rowStart + plusIndent + 7, rowStart + indent, y + PLUSY + 4);
2245 if(y >= clientSize.h)
2248 // Root Vertical Lines
2249 if(style.rootCollapse && rows.first)
2254 y = -scroll.y + ((style.header) ? rowHeight : 0);
2256 for(child = rows.first; child && child != rows.last; )
2259 if(child.subRows.first && !child.collapsed && child != rows.last)
2260 child = child.subRows.first;
2265 for(; child; child = child.parent)
2275 y2 = y + numRows * rowHeight + PLUSY + 4;
2276 surface.VLine(y1, y2, -scroll.x + 11);
2278 surface.LineStipple(0);
2281 for(row = firstRowShown; row; row = row.GetNextRow() )
2283 int x = -scroll.x + EXTRA_SPACE / 2-1;
2286 Color foreground = this.foreground /*black*/, background = this.background /*white*/;
2287 DataDisplayFlags dataDisplayFlags = 0;
2288 int rowStart = -scroll.x;
2291 Bitmap icon = row.icon ? row.icon.bitmap : null;
2292 int collapseRowStart;
2293 bool lastWasHeader = row.header;
2295 for(parent = row.parent; parent; parent = parent.parent)
2297 if(!parent.header || lastWasHeader)
2299 if(style.treeBranch)
2305 if(style.rootCollapse) indent += 20;
2308 dataDisplayFlags.fullRow = style.fullRowSelect;
2309 dataDisplayFlags.active = isActive;
2310 dataDisplayFlags.header = row.header;
2315 collapseRowStart = rowStart;
2317 if(!(style.treeBranch))
2324 if(style.multiSelect)
2326 dataDisplayFlags.selected = row.selectedFlag == selected || row.selectedFlag == tempSelected;
2327 dataDisplayFlags.current = row == currentRow || (!currentRow && row == firstRowShown);
2331 dataDisplayFlags.selected = row.selectedFlag == selected || row.selectedFlag == tempSelected;
2332 dataDisplayFlags.current = row == currentRow || (!currentRow && row == firstRowShown);
2334 if(row == currentRow)
2336 dataDisplayFlags.current = true;
2337 dataDisplayFlags.selectedFlag = true;
2339 else if(!currentRow && row == firstRowShown)
2341 dataDisplayFlags.current = true;
2345 surface.TextOpacity(true);
2347 background = this.background;
2348 foreground = this.foreground;
2350 // Draw the current row background
2353 Color colors[] = { formColor, azure, mistyRose, linen, floralWhite, lavender, lavenderBlush, lemonChiffon };
2356 while(p = p.parent) level++;
2357 background = colors[(level % (sizeof(colors)/sizeof(colors[0]))];
2358 surface.SetBackground(background);
2359 surface.Area(rowStart, y, clientSize.w, (y + rowHeight) - 1);
2360 foreground = branchesColor;
2362 else if(dataDisplayFlags.selected)
2364 if(dataDisplayFlags.selected && (isActive || style.alwaysHL || (style.alwaysEdit && style.fullRowSelect)))
2366 if(!isActive && style.alwaysEdit)
2367 background = formColor;
2369 background = selectionColor ? selectionColor : SELECTION_COLOR;
2370 if(style.fullRowSelect)
2372 int offset = (style.alwaysEdit) ? 2 : 1;
2373 surface.SetBackground(background);
2374 surface.Area(rowStart, y, clientSize.w, (y + rowHeight) - offset);
2376 if(isActive || !(style.alwaysEdit))
2377 foreground = selectionText ? selectionText : SELECTION_TEXT;
2379 foreground = branchesColor;
2385 surface.Blit(icon, x + (20 - icon.width) /2,y + 2,0,0, icon.width, icon.height);
2391 int width = clientSize.w;
2393 dataDisplayFlags.firstField = true;
2394 clip.left = x - EXTRA_SPACE / 2+1;
2396 clip.right = x + width - EXTRA_SPACE/2 - 0;
2397 clip.bottom = y + rowHeight - 1;
2398 surface.Clip(&clip);
2400 surface.TextFont(font);
2402 surface.SetForeground(foreground);
2403 surface.SetBackground(background);
2405 class(String)._vTbl[__ecereVMethodID_class_OnDisplay](class(String), "(none)", surface, x, y - 1 + (rowHeight - fontH)/2, width - EXTRA_SPACE/2, null, Alignment::left, dataDisplayFlags);
2409 if(!opacity) surface.TextOpacity(false);
2411 for(field = fields.first; field; field = field.next)
2414 int width = ((!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) || row.header) ?
2415 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2417 // Box clip = { x, y+1, x + field.width - EXTRA_SPACE - 1, y + rowHeight - 2 };
2420 //width -= EXTRA_SPACE;
2422 if(!field.prev) width -= indent;
2425 dataDisplayFlags.firstField = field.prev ? false : true;
2427 if(!dataDisplayFlags.firstField && !dataDisplayFlags.fullRow)
2429 background = this.background;
2430 foreground = this.foreground;
2433 if(!isActive && dataDisplayFlags.selected && style.alwaysEdit && field.editable && opacity)
2436 surface.SetBackground(background);
2437 surface.Area(x-3, y, x+width-1, y + rowHeight-2);
2440 clip.left = x - EXTRA_SPACE / 2+1;
2442 clip.right = x + width - EXTRA_SPACE/2 - 0;
2443 clip.bottom = y + rowHeight - 1;
2444 surface.Clip(&clip);
2446 for(index = 0, cell = row.cells.first; cell && index != field.index; index++, cell = cell.next);
2447 // Should always be as many cells in the row as fields in the listbox
2448 if(cell && cell.isSet && field.dataType)
2451 surface.TextFont(boldFont);
2453 surface.TextFont(font);
2455 surface.SetForeground(foreground);
2456 surface.SetBackground(background);
2458 if(field.dataType.type == noHeadClass || field.dataType.type == normalClass)
2459 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);
2461 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);
2464 if(!isActive && dataDisplayFlags.selected && style.alwaysEdit && field.editable)
2465 background = formColor;
2467 if(!dataDisplayFlags.firstField && !dataDisplayFlags.fullRow)
2469 background = formColor;
2470 foreground = this.background;
2473 x += width;// + EXTRA_SPACE;
2475 if(row.header) break;
2481 int plusIndent = (style.treeBranch) ? (indent - 20 + 4) : indent;
2483 if(row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)))
2485 surface.SetForeground(row.header ? headerCollapseForeground : this.foreground);
2486 surface.Rectangle(collapseRowStart + 3 + plusIndent, y + PLUSY, collapseRowStart + 11 + plusIndent, y + PLUSY + 8);
2488 surface.SetBackground(row.header ? (formColor) : (this.background)); //white
2489 surface.Area(collapseRowStart + 4 + plusIndent, y + PLUSY + 1, collapseRowStart + 10 + plusIndent, y + PLUSY + 7);
2491 surface.HLine(collapseRowStart + 5 + plusIndent, collapseRowStart + 9 + plusIndent, y+PLUSY+4);
2493 surface.VLine(y + PLUSY + 2, y + PLUSY + 6, collapseRowStart + 7 + plusIndent);
2498 // Draw the current row stipple
2499 if(style.fullRowSelect && !(style.alwaysEdit) && (dataDisplayFlags.current) && isActive)
2504 surface.LineStipple(0x5555);
2505 if(dataDisplayFlags.selected)
2506 surface.SetForeground(stippleColor);
2508 surface.SetForeground(this.foreground);
2511 surface.SetForeground(selectionColor ? selectionColor : SELECTION_COLOR);
2512 surface.Rectangle(0, y, clientSize.w-1, (y + rowHeight) - 1);
2513 surface.LineStipple(0);
2517 if(y >= clientSize.h)
2520 if(firstRowShown) surface.Clip(null);
2521 if(this.dragRow && this.dropIndex != -1)
2523 int dropIndex = this.dropIndex;
2526 if(!style.multiSelect && currentRow.index < this.dropIndex)
2528 surface.DrawingChar(223);
2530 y = style.header ? rowHeight : 0;
2531 y += dropIndex * rowHeight - scroll.y;
2533 surface.SetForeground(Color { 85, 85, 255 });
2534 surface.HLine(0, clientSize.w-1, y);
2535 surface.HLine(0, clientSize.w-1, y + 1);
2539 void OnDrawOverChildren(Surface surface)
2541 if(draggingField && this.dropField)
2543 int position = this.dropField.x;
2544 if(draggingField.x < position)
2545 position += this.dropField.width + EXTRA_SPACE;
2547 surface.SetForeground(Color { 85, 85, 255 });
2548 surface.VLine(0, rowHeight - 1, position - scroll.x - 2);
2549 surface.VLine(0, rowHeight - 1, position - scroll.x);
2551 if(sortField && !style.clearHeader && style.header)
2553 DataField field = sortField;
2554 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2555 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2558 surface.TextExtent(field.header, strlen(field.header), &tw, &th);
2559 if(tw < width - EXTRA_SPACE)
2561 bool up = field.sortOrder == 1;
2565 field.x + 2 - scroll.x, 0,
2566 field.x + width + EXTRA_SPACE - 1 - scroll.x, rowHeight
2568 surface.Clip(&clip);
2569 if(field.alignment == left || field.alignment == center)
2571 if(field.alignment == center)
2572 x = field.x + (width + EXTRA_SPACE - tw) / 2 + tw + EXTRA_SPACE + 4;
2574 x = field.x + tw + EXTRA_SPACE + 4;
2576 x = Min(x, field.x + width - 4);
2578 else if(field.alignment == right)
2580 x = field.x + width - tw - 2*EXTRA_SPACE - 4;
2581 x = Max(x, field.x + 2);
2587 // surface.SetForeground((wmenu.selectedFlag == item) ? white : black);
2588 // surface.WriteText(clientSize.w-8, y+(wmenu.rh - 8)/2, "\020", 1);
2594 surface.SetForeground(Color { 128,128,128 } );
2595 surface.DrawLine(x + 3, y, x, y + 5);
2596 surface.PutPixel(x + 1, y + 5);
2597 surface.PutPixel(x + 1, y + 3);
2598 surface.PutPixel(x + 2, y + 1);
2600 surface.SetForeground(white);
2601 surface.DrawLine(x + 4, y, x + 7, y + 5);
2602 surface.PutPixel(x + 6, y + 5);
2603 surface.PutPixel(x + 6, y + 3);
2604 surface.PutPixel(x + 5, y + 1);
2606 surface.DrawLine(x, y + 6, x + 7, y + 6);
2610 surface.SetForeground(Color { 128,128,128 });
2611 surface.DrawLine(x + 3, y+6, x, y+1);
2612 surface.PutPixel(x + 1, y+1);
2613 surface.PutPixel(x + 1, y+3);
2614 surface.PutPixel(x + 2, y+5);
2616 surface.SetForeground(white);
2617 surface.DrawLine(x + 4, y+6, x + 7, y+1);
2618 surface.PutPixel(x + 6, y+1);
2619 surface.PutPixel(x + 6, y+3);
2620 surface.PutPixel(x + 5, y+5);
2622 surface.DrawLine(x, y, x + 7, y);
2631 void OnResize(int w, int h)
2634 bool showEndBevel = false;
2636 if(style.collapse && !style.treeBranch)
2638 for(field = fields.first; field; field = field.next)
2640 int width = field.width + EXTRA_SPACE;
2648 (rowCount * rowHeight) +
2649 ((style.header) ? rowHeight : 0) -
2650 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
2652 for(field = fields.first; field; field = field.next)
2654 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2655 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2656 if(style.header && field.headButton)
2658 showEndBevel = true;
2661 field.headButton.position = { field.x, 0 };
2662 field.headButton.size = { width, rowHeight };
2663 field.headButton.visible = true;
2666 field.headButton.visible = false;
2670 if(!style.fillLastField && showEndBevel && endBevel)
2672 endBevel.position = { x, 0 };
2673 endBevel.size = { clientSize.w + 2 - x, rowHeight };
2674 endBevel.visible = true;
2677 endBevel.visible = false;
2679 if(style.alwaysEdit && editData && editData.visible)
2681 HideEditBox(true, false, true);
2685 void AdaptToFieldWidth(DataField field, bool doScroll)
2687 OnResize(clientSize.w, clientSize.h);
2689 // Scroll appropriately
2692 if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x &&
2693 field.x >= field.x + field.width + EXTRA_SPACE - clientSize.w)
2695 SetScrollPosition(field.x + field.width + EXTRA_SPACE - clientSize.w, scroll.y);
2697 else if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x ||
2699 SetScrollPosition(field.x, scroll.y);
2704 bool HeaderPushed(Button control, int x, int y, Modifiers mods)
2706 DataField field = (DataField)control.id;
2707 // false: dont destroy edit box
2708 HideEditBox(true, false, true);
2709 if(style.resizable && ((!field && x < RESIZE_BORDER && fields.last) ||
2710 (field && x < RESIZE_BORDER && field.prev) ||
2711 (field && x >= control.clientSize.w - RESIZE_BORDER)))
2714 field = fields.last;
2715 else if(x < RESIZE_BORDER && field.prev)
2718 if(field.fixed) return false;
2719 resizingField = field;
2720 this.resizeX = x + control.position.x;
2721 this.startWidth = field.width;
2722 this.oldX = x - scroll.x;
2727 if(field.fixed) return false;
2728 draggingField = field;
2729 if(style.moveFields)
2730 field.headButton.stayDown = true;
2731 else if(!style.sortable)
2739 bool HeaderMouseMove(Button control, int x, int y, Modifiers mods)
2744 DataField field = resizingField;
2746 x += control.position.x;
2748 // Tweak to prevent shrinking field if we're actually moving right
2749 if(x - scroll.x > this.oldX &&
2750 this.startWidth + x - this.resizeX < field.width)
2752 this.oldX = x - scroll.x;
2755 this.oldX = x - scroll.x;
2757 field.width = this.startWidth + x - this.resizeX;
2758 field.width = Max(field.width, - EXTRA_SPACE);
2760 AdaptToFieldWidth(field, true);
2762 else if(draggingField)
2764 x += control.position.x;
2765 if(style.moveFields)
2767 DataField field = fields.last;
2769 for(field = fields.first; field; field = field.next)
2771 fieldX += ((field.width || style.resizable) ?
2772 field.width : clientSize.w) + EXTRA_SPACE;
2776 if(draggingField == field)
2778 // Reset scroll position
2779 if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x &&
2780 field.x >= field.x + field.width + EXTRA_SPACE - clientSize.w)
2783 field.x + field.width + EXTRA_SPACE - clientSize.w,
2786 else if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x ||
2788 SetScrollPosition(field.x, scroll.y);
2791 if(this.dropField != field)
2793 this.dropField = field;
2796 int position = field.x;
2798 if(draggingField.x < position)
2800 position += field.width + EXTRA_SPACE - clientSize.w;
2801 if(position > scroll.x)
2802 SetScrollPosition(position, scroll.y);
2807 if(position < scroll.x)
2808 SetScrollPosition(position, scroll.y);
2811 this.movingFields = true;
2817 else if(style.resizable)
2819 DataField field = (DataField)control.id;
2822 if(x < RESIZE_BORDER && field.prev)
2824 if(!field.prev.fixed)
2825 control.cursor = guiApp.GetCursor(sizeWE);
2827 else if(x >= control.clientSize.w - RESIZE_BORDER)
2828 control.cursor = guiApp.GetCursor(sizeWE);
2830 control.cursor = null;
2834 if(x < RESIZE_BORDER && fields.last)
2835 control.cursor = guiApp.GetCursor(sizeWE);
2837 control.cursor = null;
2843 bool HeaderReleased(Button control, int x, int y, Modifiers mods)
2847 NotifyResized(master, this, resizingField, mods);
2848 resizingField = null;
2855 if(style.moveFields)
2860 DataField switchField = fields.last;
2864 x += draggingField.x;
2865 for(field = fields.first; field; field = field.next)
2867 fieldX += ((field.width || style.resizable) ?
2868 field.width : clientSize.w) + EXTRA_SPACE;
2871 switchField = field;
2875 if(switchField && draggingField != switchField && this.dropField)
2877 for(field = fields.first; field; field = field.next)
2879 if(field == switchField || field == draggingField)
2883 // Switch field first: move before
2884 if(field == switchField)
2885 draggingField.Move(switchField.prev);
2886 // Dragged field first: move after
2888 draggingField.Move(switchField);
2890 NotifyMovedField(master, this, draggingField, mods);
2892 draggingField.headButton.stayDown = false;
2897 movingFields = false;
2899 draggingField = null;
2905 bool HeaderClicked(Button control, int x, int y, Modifiers mods)
2907 if(style.header && !this.dropField && style.sortable)
2909 DataField field = (DataField)control.id;
2910 if(sortField == field)
2911 field.sortOrder *= -1;
2916 Sort(sortField, field.sortOrder);
2917 NotifySort(master, this, field, mods);
2923 bool HeaderDoubleClicked(Button control, int x, int y, Modifiers mods)
2927 DataField field = (DataField)control.id;
2930 if(x < RESIZE_BORDER && field.prev)
2932 else if(x >= control.clientSize.w - RESIZE_BORDER);
2938 if(x < RESIZE_BORDER && fields.last)
2939 field = fields.last;
2951 if(style.freeSelect)
2956 this.rolledOver = this.dragging = false;
2963 bool OnLoadGraphics()
2965 display.FontExtent(fontObject, "W", 1, null, &fontH);
2966 if(!style.heightSet)
2968 rowHeight = Max(fontH + 2, 16) + (style.alwaysEdit ? 1 : 0);
2969 SetScrollLineStep(8, rowHeight);
2974 void OnApplyGraphics()
2976 SetScrollLineStep(8, rowHeight);
2980 for(field = fields.first; field; field = field.next)
2982 if(field.headButton)
2984 field.headButton.bevel = (!guiApp.textMode && !style.clearHeader);
2986 field.headButton.background = Color { 0, 170, 0 };
2990 OnResize(clientSize.w, clientSize.h);
2993 bool OnResizing(int *w, int *h)
2997 if(!initSize.w && (!anchor.left.type || !anchor.right.type) /**w*/)
3002 Font font = fontObject;
3003 Font boldFont = this.boldFont.font;
3004 Display display = this.display;
3006 for(row = rows.first; row; row = row.GetNextRow())
3008 Bitmap icon = row.icon ? row.icon.bitmap : null;
3009 int x = -scroll.x + EXTRA_SPACE / 2-1;
3013 for(parent = row.parent; parent; parent = parent.parent)
3017 if(style.treeBranch)
3023 if(style.rootCollapse) indent += 20;
3025 if(style.collapse && !(style.treeBranch)) x += 15;
3029 // Compute the rows size
3030 for(field = fields.first; field; field = field.next)
3032 if(((style.resizable && (!(style.alwaysEdit) || field.next)) || field.width) && !row.header)
3033 x += field.width - (field.prev ? 0 : indent);
3038 for(index = 0, cell = row.cells.first; index != field.index; index++, cell = cell.next);
3040 // Should always be as many cells in the row as fields in the listbox
3041 if(cell && cell.isSet && field.dataType)
3043 static char tempString[4096];
3046 if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
3047 string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, cell.data[0], tempString, field.userData, null);
3049 string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, cell.data, tempString, field.userData, null);
3051 if(!string) string = "";
3052 display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, &th);
3055 display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, &th);
3057 display.FontExtent(row.header ? boldFont : font, "", 0, &tw, &th);
3060 if(row.header) break;
3064 maxWidth = Max(maxWidth, x);
3070 *h = Min(this.maxShown, this.rowCount) * rowHeight;
3075 if(!*w) *w = rowHeight * 5;
3076 if(!*h) *h = rowHeight * 5;
3083 FontResource font = this.font;
3084 FontResource boldFont
3086 faceName = font.faceName, size = font.size, bold = true
3088 AddResource(boldFont);
3089 RemoveResource(this.boldFont);
3090 this.boldFont = boldFont;
3094 SetInitSize(initSize);
3097 bool OnMouseMove(int x, int y, Modifiers mods)
3099 bool isTimer = false;
3100 int realX = x, realY = y;
3102 if(insideNotifySelect) return true;
3104 if(style.alwaysEdit && style.resizable &&
3105 resizingField && !(mods.isSideEffect))
3108 DataField field = resizingField;
3109 field.width = this.startWidth + x - this.resizeX;
3110 field.width = Max(field.width, - EXTRA_SPACE);
3112 AdaptToFieldWidth(field, true);
3116 if(style.alwaysEdit && style.resizable)
3118 int vx = -scroll.x - 1;
3121 if(style.collapse && !(style.treeBranch))
3124 for(field = fields.first; field; field = field.next)
3126 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3127 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3133 cursor = guiApp.GetCursor(sizeWE);
3137 vx += width + EXTRA_SPACE;
3141 if((editData && editData.visible) || (style.alwaysEdit))
3144 if(x == MAXINT && y == MAXINT)
3151 // ADDED THIS CHECK FOR FieldDropBox LEAKS
3152 if(/*!mods.isSideEffect && */(this.rolledOver || !this.dragging))
3154 int rowY = (style.header) ? rowHeight : 0;
3162 ((vertScroll && vertScroll.visible &&
3163 (y < 0 || y >= clientSize.h)) ||
3164 (horzScroll && horzScroll.visible &&
3165 (x < 0 || x >= clientSize.w))))
3170 if(vertScroll && vertScroll.visible &&
3171 (y < 0 || y >= clientSize.h))
3172 vertScroll.Action((y<0)?up:down, 0, 0);
3173 if(horzScroll && horzScroll.visible &&
3174 (x < 0 || x >= clientSize.w))
3175 horzScroll.Action((x<0)?up:down, 0, 0);
3181 // This must be done after the scrolling took place
3182 rowIndex = firstRowShown ? firstRowShown.index : -1;
3184 y = Min(y, clientSize.h-1);
3185 for(row = firstRowShown; row; row = row.GetNextRow(), rowIndex ++)
3194 if(row && currentRow != row)
3196 if(this.dragRow && style.moveRows)
3198 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
3200 else if(style.multiSelect)
3203 for(thisRow = rows.first; thisRow; thisRow = thisRow.GetNextRow())
3204 if((thisRow.selectedFlag == selected || thisRow.selectedFlag == tempSelected) ||
3210 if(this.dropIndex != rowIndex)
3212 this.dropIndex = rowIndex;
3213 this.editRow = null;
3215 this.movedRow = true;
3218 else if((style.freeSelect || this.dragging) && ((realX>= 0 && realY >= 0 && realX< clientSize.w && realY < clientSize.h) || this.rolledOver))
3220 if(!(style.multiSelect))
3222 if(currentRow)currentRow.selectedFlag = unselected;
3223 if(row)row.selectedFlag = selected;
3227 if(style.multiSelect)
3231 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3233 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3234 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3237 if(rowIndex >= clickedRow.index)
3239 for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
3241 selRow.selectedFlag = (selRow.selectedFlag == selected) ? tempUnselected : tempSelected;
3248 for(selRow = row; selRow; selRow = selRow.GetNextRow())
3250 selRow.selectedFlag = (selRow.selectedFlag == selected) ? tempUnselected : tempSelected;
3251 if(selRow == clickedRow)
3257 if(style.freeSelect)
3258 NotifyHighlight(master, this, currentRow, mods);
3261 insideNotifySelect = true;
3262 NotifySelect(master, this, currentRow, mods);
3263 insideNotifySelect = false;
3266 if(style.alwaysEdit && currentRow)
3267 currentRow.Edit(currentField);
3274 bool OnMouseOver(int x, int y, Modifiers mods)
3277 this.rolledOver = true;
3281 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
3283 // TOCHECK: WAS THIS MISSING ? CHECK FOR SLOWDOWN
3284 if(!active) Update(null);
3286 if(!active && (!swap || !swap.isModal))
3288 // true: destroy edit box
3289 HideEditBox(true, true, false);
3291 else if(!swap || !swap.isModal)
3293 // Bring back edit box
3294 if(currentRow && style.alwaysEdit)
3296 currentRow.Edit(currentField ? currentField : null);
3300 return true; //NotifyActivate(master, this, active, swap, 0);
3304 bool OnButtonDown(int x, int y, Modifiers mods, bool right)
3307 // Check to see if we're dragging the vertical divider
3308 if(style.alwaysEdit && style.resizable && !right)
3310 int vx = -scroll.x - 1;// + EXTRA_SPACE;// / 2 - 1;
3313 if(style.collapse && !(style.treeBranch))
3316 for(field = fields.first; field; field = field.next)
3318 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3319 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3325 resizingField = field.prev;
3327 this.startWidth = resizingField.width;
3329 SetMouseRangeToClient();
3333 vx += width + EXTRA_SPACE;
3337 if(!(style.freeSelect))
3339 int rowY = (style.header) ? rowHeight : 0;
3341 int rowIndex = firstRowShown ? firstRowShown.index : -1;
3342 DataRow previousRow = currentRow;
3343 DataRow newCurrentRow = null;
3344 DataField newCurrentField = null;
3345 bool moveMultiple = false;
3346 int numSelected = 0;
3347 int rowStart = -scroll.x;
3349 if(style.multiSelect)
3356 for(row = rows.first; row; row = row.GetNextRow())
3358 if(row.selectedFlag == tempSelected)
3359 row.selectedFlag = selected;
3360 else if(row.selectedFlag == tempUnselected)
3361 row.selectedFlag = unselected;
3362 if(row.selectedFlag == selected)
3369 for(row = firstRowShown; row; row = row.GetNextRow(), rowIndex ++)
3372 if(rowY > y || (style.multiSelect && !row.GetNextRow()))
3375 if(style.treeBranch)
3378 for(parent = (style.rootCollapse) ? row.parent : (row.parent ? row.parent.parent : null); parent; parent = parent.parent)
3384 /* THIS WAS TOO STRICT:
3385 if(style.collapse && row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)) &&
3386 (x >= rowStart + 3 + plusIndent && y >= rowY - rowHeight + PLUSY && x <= rowStart + 11 + plusIndent && y <= rowY - rowHeight + PLUSY + 8))
3388 if(style.collapse &&
3389 (x >= rowStart && y >= rowY - rowHeight && x <= rowStart + 18 + plusIndent && y <= rowY + rowHeight-1))
3391 if(row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)) && x >= plusIndent)
3392 row.collapsed = !row.collapsed;
3399 newCurrentRow = row;
3401 if(style.multiSelect)
3403 // Deselect everything if user didn't clicked on a row
3407 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3408 selRow.selectedFlag = unselected;
3410 //this.clickedRowIndex = rowIndex;
3412 else if(style.moveRows && !(mods.shift) &&
3413 (row.selectedFlag == selected || row.selectedFlag == tempSelected) &&
3414 !right && !(mods.isActivate))
3415 moveMultiple = true;
3421 if(row.selectedFlag == tempUnselected || row.selectedFlag == unselected)
3423 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3424 selRow.selectedFlag = unselected;
3425 row.selectedFlag = selected;
3428 //this.clickedRowIndex = rowIndex;
3434 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3435 selRow.selectedFlag = unselected;
3439 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3441 if(selRow != clickedRow)
3443 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3444 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3451 if(rowIndex >= clickedRow.index)
3453 for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
3457 if(selRow != clickedRow)
3459 if(selRow.selectedFlag)
3460 selRow.selectedFlag = tempUnselected;
3462 selRow.selectedFlag = tempSelected;
3466 selRow.selectedFlag = selected;
3473 for(selRow = row; selRow; selRow = selRow.GetNextRow())
3477 if(selRow != clickedRow)
3479 if(selRow.selectedFlag)
3480 selRow.selectedFlag = tempUnselected;
3482 selRow.selectedFlag = tempSelected;
3486 selRow.selectedFlag = selected;
3487 if(selRow == clickedRow)
3496 if(row.selectedFlag)
3497 row.selectedFlag = tempUnselected;
3498 else row.selectedFlag = tempSelected;
3501 row.selectedFlag = tempSelected;
3503 //this.clickedRowIndex = rowIndex;
3513 // true: destroy edit box
3516 incref newCurrentRow;
3519 if(currentRow != newCurrentRow)
3520 HideEditBox(true, true, false);
3524 if(newCurrentRow._refCount <= 1)
3525 delete newCurrentRow;
3527 newCurrentRow._refCount--;
3532 if(!(style.multiSelect))
3534 if(currentRow) currentRow.selectedFlag = unselected;
3535 if(newCurrentRow) newCurrentRow.selectedFlag = selected;
3539 if(currentRow != newCurrentRow)
3542 // true: destroy edit box
3545 //incref newCurrentRow;
3546 incref newCurrentRow;
3549 HideEditBox(true, true, false);
3554 int headerSize = ((style.header) ? rowHeight : 0);
3555 int height = clientSize.h + 1 - headerSize;
3557 /*if(newCurrentRow._refCount <= 1)
3558 delete newCurrentRow;
3561 newCurrentRow._refCount--;
3562 //newCurrentRow._refCount--;
3565 currentRow = newCurrentRow;
3567 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
3568 SetScrollPosition(scroll.x,
3569 currentRow.index * rowHeight - height + rowHeight);
3570 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
3572 int line = currentRow ? currentRow.index * rowHeight : 0;
3573 //SNAPUP(line, rowHeight);
3574 SetScrollPosition(scroll.x, line);
3577 // GO THROUGH SetCurrentRow eventually?
3578 // SetCurrentRow(newCurrentRow, true);
3582 if(style.freeSelect)
3583 NotifyHighlight(master, this, currentRow, mods);
3584 else if((moveMultiple || (!(style.multiSelect) && previousRow == currentRow)) &&
3585 newCurrentRow && !(mods.shift))
3589 if(!(mods.isActivate))
3593 this.dragRow = currentRow;
3594 this.dropIndex = -1;
3595 this.movedRow = false;
3597 if(editData && editData.visible && style.alwaysEdit)
3604 if(style.collapse && !style.treeBranch)
3607 for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3609 indent += (style.treeBranch) ? 20 : 15;
3612 for(field = fields.first; field; field = field.next)
3614 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3615 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3617 if(!field.prev) width -= indent;
3618 if(x >= sx && x < sx + width)
3622 if(field == currentField)
3623 editData.Deactivate();
3626 currentRow.Edit(field);
3627 editData.Activate();
3630 else if(!(mods.ctrl) && numSelected <= 1)
3631 this.editRow = currentRow;
3633 if(style.noDragging && newCurrentRow)
3634 NotifyReclick(master, this, newCurrentRow, mods);
3638 // If the user clicked exactly on the edited field,
3640 if(editData && editData.visible && newCurrentRow)
3642 DataField field, whichField;
3646 if(style.collapse && !(style.treeBranch))
3649 whichField = currentField;
3653 for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3655 indent += (style.treeBranch) ? 20 : 15;
3659 for(field = fields.first; field; field = field.next)
3661 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3662 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3663 if(!field.prev) width -= indent;
3664 if(x >= sx && x < sx + width && newCurrentRow)
3669 if(field) //x >= sx && x < sx + width && newCurrentRow)
3671 if(field == currentField)
3672 editData.Activate();
3674 newCurrentRow.Edit(currentField);*/
3676 else if(style.noDragging && newCurrentRow)
3677 NotifyReclick(master, this, newCurrentRow, mods);
3679 else if(style.noDragging && newCurrentRow)
3680 NotifyReclick(master, this, newCurrentRow, mods);
3686 result = NotifySelect(master, this,
3687 currentRow ? currentRow : null, mods);
3688 if(result && style.alwaysEdit && currentRow)
3692 DataField field = null;
3697 if(style.collapse && !style.treeBranch)
3700 for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3702 indent += (style.treeBranch) ? 20 : 15;
3705 for(field = fields.first; field; field = field.next)
3707 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3708 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3710 if(!field.prev) width -= indent;
3711 if(x >= sx && x < sx + width)
3713 currentField = field;
3719 currentRow.Edit(currentField);
3721 // If the user clicked exactly on the edited field,
3723 if(editData && editData.visible && newCurrentRow)
3727 editData.Activate();
3729 else if(style.noDragging && newCurrentRow)
3730 NotifyReclick(master, this, newCurrentRow, mods);
3733 else if(style.noDragging && newCurrentRow)
3734 NotifyReclick(master, this, newCurrentRow, mods);
3738 For drop box to capture...
3741 if(x < 0 || y < 0 || x >= clientSize.w || y >= clientSize.h)
3744 master.parent.Activate();
3753 if(!style.noDragging)
3755 this.dragging = true;
3758 if(x >= 0 && y >= 0 && x < clientSize.w && y < clientSize.h)
3759 this.rolledOver = true;
3764 this.dragging = false;
3765 OnLeftButtonUp(x, y, mods);
3770 bool OnLeftButtonDown(int x, int y, Modifiers mods)
3772 return OnButtonDown(x,y, mods, false);
3775 bool OnLeftButtonUp(int x, int y, Modifiers mods)
3777 if(resizingField && style.alwaysEdit)
3779 Window::FreeMouseRange();
3781 resizingField = null;
3784 if(dragRow || editRow)
3786 DataRow row, switchRow = rows.last;
3787 int rowY = (style.header) ? rowHeight : 0;
3788 for(row = firstRowShown; row; row = row.GetNextRow())
3797 if(this.editRow == switchRow && y >= 0)
3802 for(field = fields.first; field; field = field.next)
3804 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3805 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3808 if(fieldX > x + scroll.x)
3812 if(field && field.editable)
3814 // true: destroy edit box
3815 HideEditBox(true, true, false);
3816 PopupEditBox(field, false);
3818 else if(!style.noDragging)
3819 NotifyReclick(master, this, currentRow, mods);
3821 else if(style.moveRows && switchRow)
3823 if(this.dragRow == switchRow && this.movedRow == false)
3825 DataRow row = this.dragRow;
3829 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3830 selRow.selectedFlag = unselected;
3834 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3836 if(selRow != clickedRow)
3838 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3839 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3845 if(row.selectedFlag)
3846 row.selectedFlag = tempUnselected;
3847 else row.selectedFlag = tempSelected;
3850 row.selectedFlag = tempSelected;
3855 if(style.multiSelect)
3857 if(!switchRow.selectedFlag)
3859 bool foundSwitch = false;
3862 DataRow afterRow = switchRow.prev;
3863 for(row = rows.first; row; row = next)
3865 next = row.GetNextRow();
3866 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
3868 if(!foundSwitch && !after)
3871 afterRow = switchRow;
3873 if(!after || !(row.selectedFlag == selected || row.selectedFlag == tempSelected) ||
3880 else if(row == switchRow)
3887 for(row = rows.first; row; row = row.GetNextRow())
3889 if(row == switchRow || row == this.dragRow)
3893 // Switch row first: move before
3894 if(row == switchRow)
3896 if(NotifyMove(master, this, switchRow.prev, mods))
3897 dragRow.Move(switchRow.prev);
3899 // Dragged row first: move after
3902 if(NotifyMove(master, this, switchRow, mods))
3903 dragRow.Move(switchRow);
3916 if(this.dragging || style.freeSelect)
3920 this.rolledOver = this.dragging = false;
3922 if(x >= 0 && y >= 0 && x < clientSize.w && y < clientSize.h && currentRow && style.freeSelect)
3926 result = NotifySelect(master, this, currentRow, mods);
3927 if(style.alwaysEdit)
3928 currentRow.Edit(currentField);
3932 // if(!(style.freeSelect))
3938 bool OnLeftDoubleClick(int x, int y, Modifiers mods)
3940 int rowStart = -scroll.x;
3942 int rowY = (style.header) ? rowHeight : 0;
3945 OnLeftButtonUp(x,y,mods);
3946 if(style.alwaysEdit)
3948 if(!(style.collapse) || x > 15)
3949 if(editData && editData.visible)
3951 editData.Activate();
3952 NotifyDoubleClick(master, this, x, y, mods);
3956 for(row = firstRowShown; row; row = row.GetNextRow())
3959 if(rowY > y || (style.multiSelect && !row.GetNextRow()))
3961 if(style.treeBranch)
3964 for(parent = (style.rootCollapse) ? row.parent : (row.parent ? row.parent.parent : null); parent; parent = parent.parent)
3973 if((row && style.collapse && (x >= rowStart && x <= rowStart + 18 + plusIndent)) ||
3974 NotifyDoubleClick(master, this, x, y, mods))
3978 if(row && row.subRows.first)
3980 row.collapsed = !row.collapsed;
3984 // We need to return true here so that OnLeftButtonDown can popup the DataBox Editors
3990 bool OnRightButtonDown(int x, int y, Modifiers mods)
3992 return OnButtonDown(x,y, mods, true);
3995 bool OnRightButtonUp(int x, int y, Modifiers mods)
3997 OnLeftButtonUp(x,y,mods);
3998 return NotifyRightClick(master, this, x, y, mods);
4001 bool GoToLetter(unichar ch, bool keyHit)
4003 bool result = false;
4005 bool checkNextField = true;
4006 int len = keyHit ? 0 : strlen(typedString);
4008 typedString = renew typedString char[len + 2];
4009 typedString[len++] = (char)tolower(ch); // TODO: FIX UNICODE
4010 typedString[len] = '\0';
4012 for(field = fields.first; field; field = field.next)
4014 DataRow startRow = currentRow ? currentRow : rows.first;
4016 if(startRow && field.dataType && field.dataType._vTbl[__ecereVMethodID_class_OnGetString] && ch)
4019 bool looped = false;
4020 if(len == 1 && currentRow)
4021 startRow = (next = startRow.GetNextRow(), (next ? next : rows.first));
4023 for(row = startRow; row != startRow || !looped; next = row.GetNextRow(), row = next ? next : rows.first)
4025 void * data = row.GetData(field);
4026 char tempString[1024] = "";
4027 bool needClass = false;
4028 char * string = data ? (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass) : null;
4030 if(string && string[0])
4031 checkNextField = false;
4032 if(string && string[0] && !strnicmp(string, typedString, len))
4034 if(style.multiSelect)
4037 bool foundRow = false;
4039 //this.clickedRowIndex = 0;
4041 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4043 if(selRow == row) foundRow = true;
4044 selRow.selectedFlag = unselected;
4045 //if(!foundRow) this.clickedRowIndex++;
4047 row.selectedFlag = selected;
4049 SetCurrentRow(row, true);
4056 if(this.typingTimeOut && !keyHit)
4057 typingTimer.Start();
4058 if(!result || !this.typingTimeOut || keyHit)
4059 typedString[len-1] = '\0';
4061 if(!checkNextField || result) break;
4066 bool OnKeyDown(Key key, unichar ch)
4070 if(key == enter || key == keyPadEnter)
4072 if(editData && editData.visible && editData.active)
4074 HideEditBox(true, false, false);
4078 else if(key == escape)
4080 if(resizingField || this.movingFields || (editData && editData.visible) || this.dragRow)
4082 if(editData && editData.visible && style.alwaysEdit && !editData.active)
4084 // false: dont destroy edit box
4085 HideEditBox(false, false, false);
4088 resizingField.width = this.startWidth;
4089 AdaptToFieldWidth(resizingField, true);
4090 resizingField = null;
4093 this.dragRow = null;
4096 this.dragging = false;
4100 this.movingFields = false;
4101 draggingField = null;
4107 if(!currentField || !currentField.editable)
4108 for(field = fields.first; field; field = field.next)
4112 currentField = field;
4116 if(key == f2 && currentField && currentField.editable)
4118 PopupEditBox(currentField, false);
4119 if(editData && editData.visible)
4121 if(style.alwaysEdit)
4122 editData.Activate();
4127 if(!NotifyKeyDown(master, this, currentRow, key, ch))
4130 // Editable fields...
4133 if(style.alwaysEdit && editData && editData.visible)
4134 return editData.OnKeyDown(key, ch);
4135 return true; // We want to pick up the OnKeyHit to replace contents, but skip GoToLetter
4138 if(ch != 128 && !key.alt && !key.ctrl && GoToLetter(ch, false))
4140 /*if(inactive && window.state != Hidden)
4141 NotifyHighlight(master, this, currentRow, 0);
4144 NotifySelect(master, this, currentRow, 0);
4151 bool OnKeyHit(Key key, unichar ch)
4153 if(key.code == up && key.alt == true && key.ctrl == false && key.shift == false)
4156 if(!ch && !key.alt && !key.ctrl)
4158 key.code = (SmartKey)key.code;
4160 if(ch >= 32 && !key.alt && !key.ctrl && ch != 128)
4163 if(!currentField || !currentField.editable)
4164 for(field = fields.first; field; field = field.next)
4168 currentField = field;
4172 if(currentField && currentField.editable)
4174 if((!editData || !editData.visible) || !editData.active)
4176 PopupEditBox(currentField, false);
4177 if(editData && editData.visible)
4179 editData.Activate();
4180 editData.OnKeyHit(key, ch);
4187 if(!(style.multiSelect) && (key.ctrl))
4190 if(editData && editData.visible && ch && !key.alt && !key.ctrl && editData.active)
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);
4435 if(!NotifyKeyHit(master, this, currentRow, key, ch))
4438 if(ch != 128 && !key.alt && !key.ctrl && GoToLetter(ch, true))
4440 /*if(inactive && window.state != Hidden)
4441 return NotifyHighlight(master, this, currentRow, 0);
4444 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;