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 = value.defaultAlignment; }
61 get { return dataType; }
63 property bool editable { set { editable = value; } };
64 property Alignment alignment
69 if(headButton) headButton.alignment = value;
70 if(listBox) listBox.Update(null);
77 width = Max(value, -EXTRA_SPACE);
79 listBox.AdaptToFieldWidth(this, false);
83 property int index { get { return this ? index : 0; } };
92 for(field = listBox.fields.first; field; field = field.next)
94 if(index == value - 2)
107 for(field = listBox.fields.first; field; field = field.next)
119 property int sortOrder { get { return this ? sortOrder : 0; } };
120 property char * header
126 headButton.text = header;
129 property void * userData
137 return this ? userData : null;
140 property bool freeData
142 set { freeData = value; } get { return freeData; }
144 property DataField prev { get { return prev; } };
145 property DataField next { get { return next; } };
147 void Move(DataField after)
154 listBox.fields.Move(this, after);
157 listBox.OnResize(listBox.clientSize.w, listBox.clientSize.h);
158 listBox.Update(null);
165 // property::dataType = "String";
166 property::dataType = "char *";
178 headButton.Destroy(0);
183 listBox.fields.Remove(this);
184 for(field = listBox.fields.first; field; field = field.next)
186 if(field.index >= index)
189 if(listBox.currentField == this)
190 listBox.currentField = null;
192 listBox.OnResize(listBox.clientSize.w, listBox.clientSize.h);
197 DataField prev, next;
217 property int tag { set { tag = value; } get { return tag; } };
218 property DataRow previous { get { return prev; } };
219 property DataRow next { get { return next; } };
220 property int index { get { return (this && (!parent || parent.IsExpanded())) ? index : -1; } };
221 property char * string
223 set { SetData(listBox.fields.first, value); }
224 get { return GetData(listBox.fields.first); }
226 property bool isHeader { set { header = value; } get { return this ? header : false; } };
227 property BitmapResource icon { set { icon = value; } get { return icon; } };
228 property bool collapsed
232 if(collapsed != value)
235 if(parent.IsExpanded())
242 for(search = subRows.first; search; search = search.next)
243 search.selectedFlag = 0;
245 if(listBox.clickedRow && !listBox.clickedRow.parent.IsExpanded())
247 listBox.clickedRow = GetNextRow();
248 if(!listBox.clickedRow)
249 listBox.clickedRow = this;
251 if(listBox.currentRow && !listBox.currentRow.parent.IsExpanded())
253 listBox.SetCurrentRow(this, true);
255 if(listBox.firstRowShown && !listBox.firstRowShown.parent.IsExpanded())
257 listBox.firstRowShown = GetPrevRow();
258 if(!listBox.firstRowShown)
259 listBox.firstRowShown = this;
263 // TODO: FIX row indices
264 index = this.index+1;
265 for(search = GetNextRow(); search; search = search.GetNextRow())
266 search.index = index++;
267 listBox.rowCount = index;
269 listBox.HideEditBox(false, false, true);
271 listBox.SetScrollArea(
273 (listBox.rowCount * listBox.rowHeight) +
274 ((listBox.style.header) ? listBox.rowHeight : 0) -
275 ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
276 listBox.Update(null);
277 listBox.NotifyCollapse(listBox.master, listBox, this, value);
281 get { return this ? collapsed : false; }
283 property bool selected
289 selectedFlag = value ? selected : unselected;
290 listBox.Update(null);
293 get { return selectedFlag == selected || selectedFlag == tempSelected; }
295 property DataRow parent
299 if(this && (value != this))
302 DataRow after = value ? value.subRows.last : listBox.rows.last;
303 if(parent.IsExpanded())
305 for(search = GetNextRow(); search; search = search.GetNextRow())
310 listBox.HideEditBox(false, false, true);
313 if(this == listBox.clickedRow)
315 listBox.clickedRow = GetNextRow();
316 if(!listBox.clickedRow)
317 listBox.clickedRow = GetPrevRow();
320 if(this == listBox.currentRow)
322 DataRow newCurrentRow = GetNextRow();
323 if(!listBox.newCurrentRow)
324 listBox.newCurrentRow = GetPrevRow();
325 listBox.SetCurrentRow(newCurrentRow, true);
328 if(this == listBox.firstRowShown)
330 listBox.firstRowShown = GetPrevRow();
331 if(!listBox.firstRowShown)
332 listBox.firstRowShown = GetNextRow();
336 (parent ? parent.subRows : listBox.rows).Remove(this);
339 value.subRows.Insert(after, this);
341 listBox.rows.Insert(after, this);
345 if(value && listBox.style.expandOnAdd)
346 value.collapsed = false;
348 if(value.IsExpanded(this))
352 if(after && after.subRows.first && !after.collapsed)
354 for(search = after.subRows.last; !search.collapsed && search.subRows.last; )
355 search = search.subRows.last;
356 index = search.index + 1;
359 index = after ? (after.index + 1) : (index + 1);
363 for(search = GetNextRow(); search; search = search.GetNextRow())
366 listBox.SetScrollArea(
368 (listBox.rowCount * listBox.rowHeight) +
369 ((listBox.style.header) ? listBox.rowHeight : 0) -
370 ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
371 if(listBox.style.autoScroll)
372 listBox.SetScrollPosition(0, MAXINT - listBox.rowHeight);
374 // TESTING THIS HERE...
376 listBox.Sort(listBox.sortField, listBox.sortField.sortOrder);
379 int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
380 int height = listBox.clientSize.h + 1 - headerSize;
381 if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
382 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
383 else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
385 int line = listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0;
386 listBox.SetScrollPosition(listBox.scroll.x, line);
389 listBox.OnVScroll(0, listBox.scroll.y, 0);
391 listBox.Update(null);
399 property DataRow lastRow { get { return this ? subRows.last : null; } };
400 property DataRow firstRow { get { return this ? subRows.first : null; } };
402 void Edit(DataField field)
408 if(!field || !field.editable)
410 for(field = listBox.fields.first; field; field = field.next)
411 if(field.editable) break;
413 if(field && field.editable)
415 listBox.SetCurrentRow(this, true);
416 listBox.PopupEditBox(field, false);
422 void Move(DataRow after)
427 if(listBox && prev != after)
431 int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
432 int height = listBox.clientSize.h + 1 - headerSize;
434 if(!after || after.index < index)
436 if(after == listBox.firstRowShown.prev)
437 listBox.firstRowShown = this;
439 // All rows between AFTER (exclusive) and ROW (exclusive) are incremented by one
440 // ROW is equal to AFTER's index + 1
443 for(search = after ? after.next : listBox.rows.first; search && search != this; search = search.GetNextRow())
446 if(after && after.subRows.first && !after.collapsed)
448 for(search = after.subRows.last; !search.collapsed && search.subRows.last; )
449 search = search.subRows.last;
450 index = search.index + 1;
453 index = after ? (after.index + 1) : 0;
457 if(this == listBox.firstRowShown)
459 listBox.firstRowShown = GetNextRow();
462 // All rows between ROW (exclusive) and AFTER (inclusive) are decremented by one
463 // ROW is equal to AFTER's index
466 for(search = GetNextRow(); search; search = search.GetNextRow())
469 if(search == after) break;
471 index = after ? (after.index + 1) : 0;
473 listBox.rows.Move(this, after);
475 listBox.HideEditBox(true, false, true);
478 if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
479 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
480 else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
482 int line = listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0;
483 //SNAPUP(line, listBox.rowHeight);
484 listBox.SetScrollPosition(listBox.scroll.x, line);
487 listBox.OnVScroll(0, listBox.scroll.y, 0);
489 listBox.modifiedDocument = true;
491 listBox.Update(null);
498 any_object GetData(DataField field)
502 ListBoxCell cell = listBox.GetCell(&this, &field);
503 if(cell && cell.isSet && cell.data)
505 if((field.dataType.type == normalClass || field.dataType.type == noHeadClass))
508 return (void *)cell.data; // Cast for MemoryGuard
514 void * SetData(DataField field, any_object newData)
518 ListBoxCell cell = listBox.GetCell(&this, &field);
521 Class dataType = field.dataType;
525 if(dataType.type == normalClass || dataType.type == noHeadClass)
527 if(cell.data[0] && field.freeData)
528 dataType._vTbl[__ecereVMethodID_class_OnFree](dataType, cell.data[0]);
530 if(eClass_IsDerived(dataType, class(char *)) && field.freeData)
531 dataType._vTbl[__ecereVMethodID_class_OnCopy](dataType, cell.data, newData);
533 cell.data[0] = (void *)newData;
537 // Free old data first
538 dataType._vTbl[__ecereVMethodID_class_OnFree](dataType, cell.data);
539 dataType._vTbl[__ecereVMethodID_class_OnCopy](dataType, cell.data, newData);
543 listBox.modifiedDocument = true;
544 listBox.Update(null);
545 if(dataType && (dataType.type == normalClass || dataType.type == noHeadClass))
546 return (void *)cell.data; // Cast for MemoryGuard
554 void UnsetData(DataField field)
558 ListBoxCell cell = listBox.GetCell(&this, &field);
561 Class dataType = field.dataType;
565 if(dataType.type == normalClass || dataType.type == noHeadClass)
567 if(cell.data[0] && field.freeData)
568 dataType._vTbl[__ecereVMethodID_class_OnFree](dataType, cell.data[0]);
573 // Free old data first
574 dataType._vTbl[__ecereVMethodID_class_OnFree](dataType, cell.data);
578 listBox.Update(null);
583 DataRow FindRow(int tag)
586 for(row = subRows.first; row; row = row.next)
588 if(!row.noneRow && row.tag == tag)
594 DataRow FindSubRow(int tag)
597 for(row = subRows.first; row; row = row.next)
599 if(!row.noneRow && row.tag == tag)
601 if(row.subRows.first)
603 DataRow subRow = row.FindSubRow(tag);
611 DataRow AddRowAfter(DataRow after)
621 subRows.Insert(after, row);
622 row.listBox = listBox;
626 for(c = 0; c<listBox.fields.count; c++)
628 for(field = listBox.fields.first; field; field = field.next)
629 if((int)field.index == c)
633 int size = (field.dataType && field.dataType.typeSize) ?
634 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
635 ListBoxCell cell = (ListBoxCell)new0 byte[size];
637 FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
646 if(after && after.subRows.first && !after.collapsed)
648 for(search = after.subRows.last; !search.collapsed && search.subRows.last; )
649 search = search.subRows.last;
650 row.index = search.index + 1;
653 row.index = after ? (after.index + 1) : (index + 1);
658 for(search = row.GetNextRow(); search; search = search.GetNextRow())
661 listBox.SetScrollArea(
663 (listBox.rowCount * listBox.rowHeight) +
664 ((listBox.style.header) ? listBox.rowHeight : 0) -
665 ((!((listBox.clientSize.h+1) % listBox.rowHeight)) ? listBox.rowHeight : 0), true);
666 if(listBox.style.autoScroll)
667 listBox.SetScrollPosition(0, MAXINT - listBox.rowHeight);
670 listBox.modifiedDocument = true;
680 return AddRowAfter(subRows.last);
684 DataRow AddStringf(char * format, ...)
689 char string[MAX_F_STRING];
692 va_start(args, format);
693 vsprintf(string, format, args);
697 row.SetData(null, string);
703 DataRow AddString(char * string)
709 row.SetData(listBox.fields.first, string);
719 subRows.offset = (uint)&((DataRow)0).prev;
724 ListBoxCell cell, next;
729 while((subRow = subRows.first))
731 subRows.Remove(subRow);
735 for(cell = cells.first; cell; cell = next, cellIndex++)
740 for(field = listBox.fields.first; field && field.index != cellIndex; field = field.next);
743 // TOCHECK: Is this check good? Will need incref/decref sometime?
744 if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
746 if(cell.data[0] && field.freeData)
747 field.dataType._vTbl[__ecereVMethodID_class_OnFree](field.dataType, cell.data[0]);
750 field.dataType._vTbl[__ecereVMethodID_class_OnFree](field.dataType, cell.data);
760 return !this || (!collapsed && (!parent || parent.IsExpanded()));
763 int Compare(DataRow b, DataField sortField)
766 ListBoxCell cell1, cell2;
768 for(index = 0, cell1 = cells.first, cell2 = b.cells.first;
769 index != sortField.index;
770 index++, cell1 = cell1.next, cell2 = cell2.next);
772 if(!cell1.isSet && !cell2.isSet)
774 else if(!cell1.isSet)
776 else if(!cell2.isSet)
779 if(noneRow && !b.noneRow) return -1;
780 else if(!noneRow && b.noneRow) return 1;
781 else if(noneRow && b.noneRow) return 0;
783 if(sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare])
785 if(sortField.dataType.type == normalClass || sortField.dataType.type == noHeadClass)
787 result = sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare](sortField.dataType,
788 (cell1.isSet && cell1.data) ? cell1.data[0] : null,
789 (cell2.isSet && cell2.data) ? cell2.data[0] : null);
793 result = sortField.dataType._vTbl[__ecereVMethodID_class_OnCompare](sortField.dataType,
794 cell1.isSet ? cell1.data : null,
795 cell2.isSet ? cell2.data : null);
798 return sortField.sortOrder * result;
801 void _SortSubRows(DataField field, int order)
804 for(search = subRows.first; search; search = search.next)
805 search._SortSubRows(field, order);
806 subRows.Sort(Compare, field);
809 public void SortSubRows(bool scrollToCurrent)
811 if(this && listBox && listBox.sortField)
813 _SortSubRows(listBox.sortField, listBox.sortField.sortOrder);
815 // TODO: Recompute row indices
818 int index = this.index;
819 for(search = this; search; search = search.GetNextRow())
820 search.index = index++;
824 int headerSize = ((listBox.style.header) ? listBox.rowHeight : 0);
825 int height = listBox.clientSize.h + 1 - headerSize;
826 if(listBox.currentRow && listBox.currentRow.index * listBox.rowHeight > listBox.scroll.y + height - listBox.rowHeight)
827 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow.index * listBox.rowHeight - height + listBox.rowHeight);
828 else if(!listBox.currentRow || listBox.currentRow.index * listBox.rowHeight < listBox.scroll.y)
829 listBox.SetScrollPosition(listBox.scroll.x, listBox.currentRow ? listBox.currentRow.index * listBox.rowHeight : 0);
830 listBox.OnVScroll(0, listBox.scroll.y, 0);
835 public DataRow GetPrevRow()
841 for(row = prev; row && !row.collapsed && row.subRows.last; row = row.subRows.last);
848 public DataRow GetNextRow()
852 if(subRows.first && !collapsed)
856 for(row = this; row; row = row.parent)
858 if(row.next) { row = row.next; break; }
867 SelectedFlag selectedFlag;
878 public class ListBox : CommonControl
880 hasVertScroll = true;
881 // background = white;
883 snapVertScroll = true;
885 class_property(icon) = "<:ecere>controls/listBox.png";
889 property bool freeSelect { property_category $"Behavior" set { style.freeSelect = value; } get { return style.freeSelect; } };
890 property DataRow currentRow { property_category $"Private" /*"Behavior"*/ set { SetCurrentRow(value, false); } get { return currentRow; } };
891 property DataField currentField
893 get { return currentField; }
894 // TODO: Needs definition of what this is, testing
897 currentField = value;
898 HideEditBox(true, true, false);
899 if(value && value.editable)
900 PopupEditBox(currentField, false);
904 property int rowHeight
906 property_category $"Appearance"
907 isset { return style.heightSet; }
912 style.heightSet = true;
914 SetScrollLineStep(8, value);
918 style.heightSet = false;
923 get { return rowHeight; }
925 property Seconds typingTimeout
927 property_category $"Behavior"
930 typedString[0] = '\0';
931 typingTimer.delay = value;
932 typingTimeOut = value;
934 get { return typingTimeOut; }
936 property bool moveRows { property_category $"Behavior" set { style.moveRows = value; } get { return style.moveRows; } };
937 property bool moveFields { property_category $"Behavior" set { style.moveFields = value; } get { return style.moveFields; } };
938 property bool resizable { property_category $"Behavior" set { style.resizable = value; } get { return style.resizable; } };
939 property bool autoScroll { property_category $"Behavior" set { style.autoScroll = value; } get { return style.autoScroll; } };
940 property bool alwaysHighLight { property_category $"Appearance" set { style.alwaysHL = value; } get { return style.alwaysHL; } };
941 property bool hasClearHeader { property_category $"Appearance" set { style.clearHeader = value; if(value) property::hasHeader = true; } get { return style.clearHeader; } };
942 property bool hasHeader
944 property_category $"Appearance"
947 if(value && !style.header)
953 bevel = !guiApp.textMode && !style.clearHeader;
954 dontScrollVert = true;
957 NotifyPushed = HeaderPushed;
958 NotifyClicked = HeaderClicked;
959 NotifyReleased = HeaderReleased;
960 NotifyMouseMove = HeaderMouseMove;
964 endBevel.visible = false;
966 style.header = value;
968 get { return style.header; }
970 property bool multiSelect { property_category $"Behavior" set { style.multiSelect = value; } get { return style.multiSelect; } };
971 property bool alwaysEdit { property_category $"Behavior" set { style.alwaysEdit = value; } get { return style.alwaysEdit; } };
972 property bool fullRowSelect { property_category $"Appearance" set { style.fullRowSelect = value; } get { return style.fullRowSelect; } };
973 property bool collapseControl { property_category $"Appearance" set { style.collapse = value; } get { return style.collapse; } };
974 property bool treeBranches { property_category $"Appearance" set { style.treeBranch = value; } get { return style.treeBranch; } };
975 property bool rootCollapseButton { property_category $"Appearance" set { style.rootCollapse = value; } get { return style.rootCollapse; } };
976 property bool sortable { property_category $"Behavior" set { style.sortable = value; } get { return style.sortable; } };
977 property bool noDragging { property_category $"Behavior" set { style.noDragging = value; } get { return style.noDragging; } };
978 property bool fillLastField
980 property_category $"Behavior"
983 style.fillLastField = value;
985 get { return style.fillLastField; }
987 property int numSelections
991 int numSelections = 0;
992 if(this && style.multiSelect)
995 for(row = rows.first; row; row = row.GetNextRow())
996 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
999 return numSelections;
1002 property int currentIndex
1004 get { return currentRow ? currentRow.index : -1; }
1006 property DataRow lastRow { get { return this ? rows.last : null; } };
1007 property DataRow firstRow { get { return this ? rows.first : null; } };
1008 property int rowCount { get { return rowCount; } };
1009 property DataField firstField { get { return this ? fields.first : null; } };
1010 property Color selectionColor { set { selectionColor = value; } get { return selectionColor; } isset { return selectionColor ? true : false; } };
1011 property Color selectionText { set { selectionText = value; } get { return selectionText; } isset { return selectionText ? true : false; } };
1012 property Color stippleColor { set { stippleColor = value; } get { return stippleColor; } };
1013 property bool expandOnAdd { set { style.expandOnAdd = value; } get { return style.expandOnAdd; } };
1016 virtual bool Window::NotifySelect(ListBox listBox, DataRow row, Modifiers mods);
1017 virtual bool Window::NotifyHighlight(ListBox listBox, DataRow row, Modifiers mods);
1018 virtual bool Window::NotifyReclick(ListBox listBox, DataRow row, Modifiers mods);
1019 virtual bool Window::NotifySort(ListBox listBox, DataField field, Modifiers mods);
1020 virtual bool Window::NotifyChanged(ListBox listBox, DataRow row);
1021 virtual bool Window::NotifyKeyDown(ListBox listBox, DataRow row, Key key, unichar ch);
1022 virtual bool Window::NotifyEdited(ListBox listBox, DataRow row);
1023 virtual bool Window::NotifyEditDone(ListBox listBox, DataRow row);
1024 virtual bool Window::NotifyMovedField(ListBox listBox, DataField field, Modifiers mods);
1025 virtual bool Window::NotifyMove(ListBox listBox, DataRow row, Modifiers mods);
1026 virtual bool Window::NotifyDoubleClick(ListBox listBox, int x, int y, Modifiers mods);
1027 virtual bool Window::NotifyRightClick(ListBox listBox, int x, int y, Modifiers mods);
1028 virtual bool Window::NotifyResized(ListBox listBox, DataField field, Modifiers mods);
1029 virtual bool Window::NotifyCollapse(ListBox listBox, DataRow row, bool collapsed);
1030 virtual bool Window::NotifyKeyHit(ListBox listBox, DataRow row, Key key, unichar ch);
1031 virtual bool Window::NotifyModified(ListBox listBox, DataRow row);
1032 virtual bool Window::NotifyEditing(ListBox listBox, DataRow row);
1035 void AddField(DataField addedField)
1040 if(fields.first && ((DataField)fields.first).defaultField)
1042 DataField defaultField = fields.first;
1044 defaultField.Free();
1045 delete defaultField;
1049 addedField = DataField { };
1053 addedField.listBox = this;
1054 fields.Add(addedField);
1056 addedField.sortOrder = 1;
1057 addedField.index = numFields;
1061 addedField.headButton.Destroy(0);
1062 delete addedField.headButton;
1063 addedField.headButton = Button
1068 dontScrollVert = true;
1069 id = (uint)addedField;
1070 text = addedField.header;
1071 bevel = (!guiApp.textMode && !style.clearHeader);
1073 alignment = addedField.alignment;
1074 NotifyPushed = HeaderPushed;
1075 NotifyClicked = HeaderClicked;
1076 NotifyReleased = HeaderReleased;
1077 NotifyMouseMove = HeaderMouseMove;
1079 incref addedField.headButton;
1080 addedField.headButton.Create();
1083 addedField.headButton.background = Color { 0, 170, 0 };
1089 for(row = rows.first; row; )
1091 int size = (field.dataType && field.dataType.typeSize) ?
1092 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1093 ListBoxCell cell = (ListBoxCell)new0 byte[size];
1094 row.cells.Add(cell);
1095 FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
1098 if(row.subRows.first)
1099 row = row.subRows.first;
1102 for(; row; row = row.parent)
1104 if(row.next) { row = row.next; break; }
1109 OnResize(clientSize.w, clientSize.h);
1118 while((field = fields.first))
1124 endBevel.visible = false;
1129 void RemoveField(DataField field)
1135 int index = field.index;
1138 for(row = rows.first; row; )
1143 for(cell = row.cells.first, c = 0; c < index && cell; c++, cell = cell.next);
1144 if(cell && index == c)
1148 // TOCHECK: Is this check good? Will need incref/decref sometime?
1149 if(field.dataType.type == normalClass || field.dataType.type == noHeadClass)
1151 if(cell.data[0] && field.freeData)
1152 field.dataType._vTbl[__ecereVMethodID_class_OnFree](field.dataType, cell.data[0]);
1155 field.dataType._vTbl[__ecereVMethodID_class_OnFree](field.dataType, cell.data);
1158 row.cells.Remove(cell);
1162 if(row.subRows.first)
1163 row = row.subRows.first;
1166 for(; row; row = row.parent)
1168 if(row.next) { row = row.next; break; }
1177 endBevel.visible = false;
1181 DataRow AddRowNone()
1183 DataRow row { noneRow = true };
1192 rows.Insert(null, row);
1195 for(search = row.GetNextRow(); search; search = search.GetNextRow())
1201 firstRowShown = row;
1205 (rowCount * rowHeight) +
1206 ((style.header) ? rowHeight : 0) -
1207 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1208 if(style.autoScroll)
1209 SetScrollPosition(0, MAXINT - rowHeight);
1210 modifiedDocument = true;
1229 // Find very last row
1232 for(lastRow = rows.last; lastRow && !lastRow.collapsed && lastRow.subRows.last; lastRow)
1233 lastRow = lastRow.subRows.last;
1234 row.index = lastRow ? (lastRow.index + 1) : 0;
1242 for(c = 0; c<fields.count; c++)
1244 for(field = fields.first; field; field = field.next)
1245 if((int)field.index == c)
1249 int size = (field.dataType && field.dataType.typeSize) ?
1250 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1251 ListBoxCell cell = (ListBoxCell) new0 byte[size];
1252 row.cells.Add(cell);
1253 FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
1260 firstRowShown = row;
1266 (rowCount * rowHeight) +
1267 ((style.header) ? rowHeight : 0) -
1268 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1269 if(style.autoScroll)
1270 SetScrollPosition(0, MAXINT - rowHeight);
1271 modifiedDocument = true;
1279 DataRow AddRowAfter(DataRow after)
1291 if(after && after.subRows.first && !after.collapsed)
1293 for(search = after.subRows.last; !search.collapsed && search.subRows.last; )
1294 search = search.subRows.last;
1295 row.index = search.index + 1;
1298 row.index = after ? (after.index + 1) : 0;
1299 rows.Insert(after, row);
1302 // TODO: FIX row indices
1303 for(search = row.GetNextRow(); search; search = search.GetNextRow())
1308 for(c = 0; c<fields.count; c++)
1310 for(field = fields.first; field; field = field.next)
1311 if((int)field.index == c)
1315 int size = (field.dataType && field.dataType.typeSize) ?
1316 (sizeof(class ListBoxCell) + field.dataType.typeSize - sizeof(void *)) : sizeof(class ListBoxCell);
1317 ListBoxCell cell = (ListBoxCell) new0 byte[size];
1318 row.cells.Add(cell);
1319 FillBytes(cell.data, 0, size - (uint)&((ListBoxCell)0).data);
1323 if(!firstRowShown || !after)
1325 firstRowShown = row;
1330 (rowCount * rowHeight) +
1331 ((style.header) ? rowHeight : 0) -
1332 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1333 if(style.autoScroll)
1334 SetScrollPosition(0, MAXINT - rowHeight);
1335 modifiedDocument = true;
1342 DataRow AddStringf(char * format, ...)
1348 char string[MAX_F_STRING];
1351 va_start(args, format);
1352 vsprintf(string, format ? format : "", args);
1356 row.SetData(fields.first, string);
1362 DataRow AddString(char * string)
1368 row.SetData(fields.first, string);
1374 void SelectRow(DataRow row)
1376 SetCurrentRow(row, true);
1379 void DeleteRow(DataRow row)
1381 if(!row) row = currentRow;
1384 DataRow sub, next, search;
1385 // Trying to move this here (Messed up deleting watches)
1386 //HideEditBox(false, false, true);
1389 for(sub = row.subRows.first; sub; sub = next)
1395 if(row.parent.IsExpanded())
1397 // TODO: FIX row indices
1398 for(search = row.GetNextRow(); search; search = search.GetNextRow())
1403 HideEditBox(false, false, true);
1405 if(row == clickedRow)
1407 clickedRow = row.GetNextRow();
1409 clickedRow = row.GetPrevRow();
1412 if(row == currentRow)
1414 DataRow newCurrentRow = row.GetNextRow();
1416 newCurrentRow = row.GetPrevRow();
1417 SetCurrentRow(newCurrentRow, true);
1420 if(row == firstRowShown)
1422 firstRowShown = row.GetPrevRow();
1424 firstRowShown = row.GetNextRow();
1427 (row.parent ? row.parent.subRows: rows).Remove(row);
1430 //HideEditBox(false, false, true);
1434 (this.rowCount * rowHeight) +
1435 ((style.header) ? rowHeight : 0) -
1436 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1438 modifiedDocument = true;
1444 DataRow FindRow(int tag)
1449 for(row = rows.first; row; row = row.next)
1451 if(!row.noneRow && row.tag == tag)
1459 DataRow FindString(char * searchedString)
1462 bool checkNextField = true;
1463 int len = searchedString ? strlen(searchedString) : 0;
1465 for(field = fields.first; field; field = field.next)
1467 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1470 for(row = rows.first; row; row = row.GetNextRow())
1474 void * data = row.GetData(field);
1475 char tempString[1024] = "";
1476 bool needClass = false;
1477 char * string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass);
1479 if(string && string[0])
1480 checkNextField = false;
1481 if(string && string[0] && !strcmp(string, searchedString))
1486 if(!checkNextField) break;
1491 DataRow FindSubString(char * subString)
1494 bool checkNextField = true;
1495 int len = subString ? strlen(subString) : 0;
1499 for(field = fields.first; field; field = field.next)
1501 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1504 for(row = rows.first; row; row = row.GetNextRow())
1508 void * data = row.GetData(field);
1509 char tempString[1024] = "";
1510 bool needClass = false;
1511 char * string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass);
1513 if(string && string[0])
1514 checkNextField = false;
1515 if(string && string[0] && !strncmp(string, subString, len))
1520 if(!checkNextField) break;
1526 DataRow FindSubStringi(char * subString)
1529 bool checkNextField = true;
1530 int len = subString ? strlen(subString) : 0;
1531 DataRow result = null;
1532 char * bestResult = null;
1537 for(field = fields.first; field; field = field.next)
1539 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1542 for(row = rows.first; row; row = row.GetNextRow())
1546 void * data = row.GetData(field);
1547 char tempString[1024] = "";
1548 bool needClass = false;
1549 char * string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass);
1551 if(string && string[0])
1552 checkNextField = false;
1553 if(string && string[0])
1555 int stringLen = strlen(string);
1557 if(!strnicmp(string, subString, Min(len, stringLen)))
1559 if(bestLen < Min(len, stringLen))
1561 if(!bestResult || strcmpi(string, bestResult) < 0)
1563 bestLen = Min(len, stringLen);
1564 bestResult = string;
1572 if(!checkNextField) break;
1578 DataRow FindSubStringAfter(DataRow after, char * subString)
1581 bool checkNextField = true;
1582 int len = subString ? strlen(subString) : 0;
1586 for(field = fields.first; field; field = field.next)
1588 if(field.dataType._vTbl[__ecereVMethodID_class_OnGetString])
1591 for(row = after.GetNextRow(); row && row != after; row = row.GetNextRow(), (!row) ? (row = rows.first) : null)
1595 void * data = row.GetData(field);
1596 char tempString[1024] = "";
1597 bool needClass = false;
1598 char * string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass);
1600 if(string && string[0])
1601 checkNextField = false;
1602 if(string && string[0] && !strncmp(string, subString, len))
1607 if(!checkNextField) break;
1613 DataRow FindSubRow(int tag)
1619 for(row = rows.first; row; row = row.next)
1621 if(!row.noneRow && row.tag == tag)
1623 if(!row.noneRow && row.subRows.first)
1625 DataRow subRow = row.FindSubRow(tag);
1639 Window master = this.master;
1641 HideEditBox(false, true, false);
1642 editData.Destroy(0);
1644 firstRowShown = currentRow = null;
1649 if(style.freeSelect)
1650 NotifyHighlight(master, this, currentRow ? currentRow : null, 0);
1652 NotifySelect(master, this, currentRow ? currentRow : null, 0);
1655 if(style.alwaysEdit && currentRow)
1656 currentRow.Edit(currentField);
1663 (this.rowCount * rowHeight) +
1664 ((style.header) ? rowHeight : 0) -
1665 ((rowHeight && !((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
1670 void Sort(DataField field, int order)
1675 int headerSize = ((style.header) ? rowHeight : 0);
1676 int height = clientSize.h + 1 - headerSize;
1678 if(!field) field = fields.first;
1680 field.sortOrder = order ? order : 1;
1681 rows.Sort(DataRow::Compare, field);
1683 for(search = rows.first; search; search = search.next)
1684 search._SortSubRows(field, order);
1686 // TODO: Recompute row indices
1689 for(search = rows.first; search; search = search.GetNextRow())
1690 search.index = index++;
1693 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
1694 SetScrollPosition(scroll.x, currentRow.index * rowHeight - height + rowHeight);
1695 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
1696 SetScrollPosition(scroll.x, currentRow ? currentRow.index * rowHeight : 0);
1698 OnVScroll(0, scroll.y, 0);
1700 // SetScrollPosition(0, scroll.y);
1705 void StopEditing(bool save)
1707 HideEditBox(save, false, true);
1710 void GetMultiSelection(OldList list)
1713 if(this && style.multiSelect)
1717 for(row = rows.first; row; row = row.GetNextRow())
1719 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
1721 list.Add(OldLink { data = row });
1727 // Convenience Current Row Methods
1728 void * SetData(DataField field, any_object data)
1730 return currentRow.SetData(field, data);
1733 any_object GetData(DataField field)
1735 return (void *)currentRow.GetData(field);
1740 return currentRow ? currentRow.tag : 0;
1746 DataField defaultField { };
1747 rows.offset = (uint)&((DataRow)0).prev;
1748 fields.offset = (uint)&((DataField)0).prev;
1749 style.fullRowSelect = true;
1750 style.fillLastField = true;
1751 style.expandOnAdd = true;
1752 typingTimeOut = 0.5;
1753 rowHeight = 16; // Stuff depending on creation and default property checking
1756 defaultField.defaultField = true;
1758 AddField(defaultField);
1760 typedString = new char[1];
1761 typedString[0] = '\0';
1776 while((field = fields.first))
1778 // fields.Remove(field);
1788 while((row = rows.first))
1795 ListBoxCell GetCell(DataRow * row, DataField * field)
1797 ListBoxCell cell = null;
1798 if(!*row) *row = currentRow;
1801 if(!*field) *field = this ? currentField : null;
1804 for(*field = fields.first; (*field).index != 0; *field = (*field).next);
1809 if(field->listBox == this)
1811 for(index = 0, cell = (*row).cells.first; cell && index != (*field).index; index++, cell = cell.next);
1818 void HideEditBox(bool save, bool alwaysStopEdit, bool repositionOnly)
1820 if(editData && editData.visible)
1822 Class dataType = currentField.dataType;
1824 editData.SaveData();
1826 editData.visible = false;
1827 NotifyEditDone(master, this, currentRow);
1829 // ENSURE DATA BOX IS NOT VISIBLE
1830 editData.visible = false;
1832 if(style.alwaysEdit && !alwaysStopEdit)
1835 int height = rowHeight - (style.alwaysEdit ? 1 : 0);
1836 int y = currentRow.index * rowHeight + (style.header ? rowHeight : 0);
1837 int x = currentField.x;
1838 int width = (!currentField.next && style.fillLastField && (!hasHorzScroll || clientSize.w - currentField.x > currentField.width + EXTRA_SPACE)) ?
1839 clientSize.w - currentField.x : (currentField.width + EXTRA_SPACE);
1841 if(!style.alwaysEdit)
1843 editData.position = { x, y };
1844 editData.size = { width, height };
1848 editData.position = { x, y - editData.clientStart.y };
1849 editData.size = { width, height + editData.clientStart.y * 2 };
1851 editData.visible = true;
1852 if(style.alwaysEdit)
1853 editData.Deactivate();
1855 PopupEditBox(currentField, repositionOnly);
1861 currentField = null;*/
1865 void SetCurrentRow(DataRow row, bool notify)
1867 if(currentRow != row || (currentRow && currentRow.selectedFlag == unselected))
1869 int headerSize = ((style.header) ? rowHeight : 0);
1870 int height = clientSize.h + 1 - headerSize;
1872 // true: destroy edit box
1873 HideEditBox(true, true, false);
1875 if(!(style.multiSelect) && currentRow)
1876 currentRow.selectedFlag = unselected;
1880 if(style.multiSelect)
1884 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
1885 selRow.selectedFlag = unselected;
1887 currentRow.selectedFlag = selected;
1892 currentRow.selectedFlag = selected;
1894 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
1895 SetScrollPosition(scroll.x,
1896 currentRow.index * rowHeight - height + rowHeight);
1897 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
1899 int line = currentRow ? currentRow.index * rowHeight : 0;
1900 //SNAPUP(line, rowHeight);
1901 SetScrollPosition(scroll.x, line);
1906 Window master = this.master;
1909 if(style.freeSelect && visible)
1910 NotifyHighlight(master, this, currentRow ? currentRow : null, 0);
1912 NotifySelect(master, this, currentRow ? currentRow : null, 0);
1913 if(style.alwaysEdit && currentRow)
1914 currentRow.Edit(currentField);
1922 void PopupEditBox(DataField whichField, bool repositionOnly)
1924 if((!editData || !editData.visible || currentField != whichField) && currentRow)
1926 // true: destroy edit box
1927 HideEditBox(true, true, false);
1930 int height = rowHeight - (style.alwaysEdit ? 1 : 0);
1932 int y = currentRow.index * rowHeight + (style.header ? rowHeight : 0);
1934 //void * data = currentRow.GetData(whichField);
1939 if(style.collapse && !(style.treeBranch))
1942 for(field = fields.first; field; field = field.next)
1944 width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
1945 clientSize.w - field.x : (field.width + EXTRA_SPACE);
1946 if(field == whichField) break;
1950 currentField = whichField;
1951 cell = GetCell(&row, ¤tField);
1958 background = dataBoxBackground;
1959 foreground = dataBoxForeground;
1961 bool NotifyChanged(bool closingDropDown)
1964 DataField field = null;
1965 ListBoxCell cell = GetCell(&row, &field);
1969 modifiedDocument = true;
1971 NotifyChanged(master, this, currentRow);
1976 bool NotifyModified()
1978 //DataRow row = null;
1979 //DataField field = null;
1980 //ListBoxCell cell = GetCell(&row, &field);
1981 //cell.isSet = true;
1982 modifiedDocument = true;
1984 NotifyModified(master, this, currentRow);
1988 bool OnKeyDown(Key key, unichar ch)
1990 bool result = DataBox::OnKeyDown(key, ch);
1991 if(visible && active) // Added this check here, because we will not use enter/escape otherwise, and lose DataBox's result
1993 if((SmartKey)key == enter || (SmartKey)key == escape)
2002 editData.Destroy(0);
2003 editData.type = whichField.dataType;
2004 editData.fieldData = whichField.userData;
2005 editData.borderStyle = style.alwaysEdit ? 0 : deep;
2006 editData.data = cell ? cell.data : null;
2009 // Might not really need this anymore...
2010 NotifyEditing(master, this, currentRow);
2013 if(!style.alwaysEdit)
2015 editData.position = { x, y - editData.clientStart.y };
2016 editData.size = { width, height + editData.clientStart.y * 2 };
2020 editData.position = { x, y };
2021 editData.size = { width, height };
2025 editData.visible = true;
2027 if(style.alwaysEdit)
2028 editData.Deactivate();
2030 // MOVED THIS HIGHER FOR DATALIST EDITOR
2032 // Might not really need this anymore...
2033 NotifyEdited(master, this, currentRow);
2038 void OnRedraw(Surface surface)
2041 int y = (style.header) ? rowHeight : 0;
2042 bool isActive = active;
2043 Font font = fontObject;
2044 Font boldFont = this.boldFont.font;
2048 if(style.alwaysEdit && style.fullRowSelect)
2051 int y = (style.header) ? rowHeight : 0;
2052 int x = -scroll.x - 1;// + EXTRA_SPACE;// / 2 - 1;
2053 int w = clientSize.w;
2054 int h = clientSize.h;
2058 // Fill out indent column
2059 if(style.collapse && !(style.treeBranch) && rows.first)
2062 surface.SetBackground(formColor);
2063 surface.Area(-scroll.x, 0, x, clientSize.h);
2066 surface.SetForeground(formColor);
2067 for(row = firstRowShown; row; row = row.GetNextRow())
2070 surface.HLine(x + 1, w-1, y-1);
2076 for(field = fields.first; field; field = field.next)
2078 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2079 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2080 if(field.prev && y > 0)
2081 surface.VLine(0, y-1, x);
2086 surface.foreground = this.foreground;
2087 surface.TextOpacity(false);
2089 // Draw the tree branches
2090 if(style.treeBranch)
2092 int y = -scroll.y + ((style.header) ? rowHeight : 0);
2093 surface.LineStipple(0x5555);
2094 surface.SetForeground(branchesColor);
2095 for(row = rows.first; row; row = row.GetNextRow() )
2097 int x = -scroll.x + EXTRA_SPACE / 2-1;
2098 int rowStart = -scroll.x;
2103 for(parent = row.parent; parent; parent = parent.parent)
2104 if(!parent.header) indent += 20;
2105 if(style.rootCollapse) indent += 20;
2107 plusIndent = (style.treeBranch) ? (indent - 20 + 4) : indent;
2112 if(row.subRows.first)
2115 int y1 = y + PLUSY + 4;
2119 for(child = row.collapsed ? null : row.subRows.first; child && child != row; )
2122 if(child.subRows.first && !child.collapsed && child != row.subRows.last)
2123 child = child.subRows.first;
2128 for(; child && child != row; child = child.parent)
2138 y2 = y + numRows * rowHeight + PLUSY + 4;
2139 surface.VLine(y1, y2, rowStart + plusIndent + 7 + 20);
2141 surface.HLine(rowStart + plusIndent + 7, rowStart + indent, y + PLUSY + 4);
2144 if(y >= clientSize.h)
2147 // Root Vertical Lines
2148 if(style.rootCollapse && rows.first)
2153 y = -scroll.y + ((style.header) ? rowHeight : 0);
2155 for(child = rows.first; child && child != rows.last; )
2158 if(child.subRows.first && !child.collapsed && child != rows.last)
2159 child = child.subRows.first;
2164 for(; child; child = child.parent)
2174 y2 = y + numRows * rowHeight + PLUSY + 4;
2175 surface.VLine(y1, y2, -scroll.x + 11);
2177 surface.LineStipple(0);
2180 for(row = firstRowShown; row; row = row.GetNextRow() )
2182 int x = -scroll.x + EXTRA_SPACE / 2-1;
2185 Color foreground = this.foreground /*black*/, background = this.background /*white*/;
2186 DataDisplayFlags dataDisplayFlags = 0;
2187 int rowStart = -scroll.x;
2190 Bitmap icon = row.icon ? row.icon.bitmap : null;
2191 int collapseRowStart;
2193 for(parent = row.parent; parent; parent = parent.parent)
2197 if(style.treeBranch)
2203 if(style.rootCollapse) indent += 20;
2206 dataDisplayFlags.fullRow = style.fullRowSelect;
2207 dataDisplayFlags.active = isActive;
2208 dataDisplayFlags.header = row.header;
2213 collapseRowStart = rowStart;
2215 if(!(style.treeBranch))
2222 if(style.multiSelect)
2224 dataDisplayFlags.selected = row.selectedFlag == selected || row.selectedFlag == tempSelected;
2225 dataDisplayFlags.current = row == currentRow || (!currentRow && row == firstRowShown);
2229 dataDisplayFlags.selected = row.selectedFlag == selected || row.selectedFlag == tempSelected;
2230 dataDisplayFlags.current = row == currentRow || (!currentRow && row == firstRowShown);
2232 if(row == currentRow)
2234 dataDisplayFlags.current = true;
2235 dataDisplayFlags.selectedFlag = true;
2237 else if(!currentRow && row == firstRowShown)
2239 dataDisplayFlags.current = true;
2243 surface.TextOpacity(true);
2245 background = this.background;
2246 foreground = this.foreground;
2248 // Draw the current row background
2251 background = formColor;
2252 surface.SetBackground(formColor);
2253 surface.Area(rowStart, y, clientSize.w, (y + rowHeight) - 1);
2254 foreground = branchesColor;
2256 else if(dataDisplayFlags.selected)
2258 if(dataDisplayFlags.selected && (isActive || style.alwaysHL || (style.alwaysEdit && style.fullRowSelect)))
2260 if(!isActive && style.alwaysEdit)
2261 background = formColor;
2263 background = selectionColor ? selectionColor : SELECTION_COLOR;
2264 if(style.fullRowSelect)
2266 int offset = (style.alwaysEdit) ? 2 : 1;
2267 surface.SetBackground(background);
2268 surface.Area(rowStart, y, clientSize.w, (y + rowHeight) - offset);
2270 if(isActive || !(style.alwaysEdit))
2271 foreground = selectionText ? selectionText : SELECTION_TEXT;
2273 foreground = branchesColor;
2279 surface.Blit(icon, x + (20 - icon.width) /2,y + 2,0,0, icon.width, icon.height);
2285 int width = clientSize.w;
2287 dataDisplayFlags.firstField = true;
2288 clip.left = x - EXTRA_SPACE / 2+1;
2290 clip.right = x + width - EXTRA_SPACE/2 - 0;
2291 clip.bottom = y + rowHeight - 1;
2292 surface.Clip(&clip);
2294 surface.TextFont(font);
2296 surface.SetForeground(foreground);
2297 surface.SetBackground(background);
2299 class(String)._vTbl[__ecereVMethodID_class_OnDisplay](class(String), "(none)", surface, x, y - 1 + (rowHeight - fontH)/2, width - EXTRA_SPACE/2, null, Alignment::left, dataDisplayFlags);
2303 if(!opacity) surface.TextOpacity(false);
2305 for(field = fields.first; field; field = field.next)
2308 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2309 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2311 // Box clip = { x, y+1, x + field.width - EXTRA_SPACE - 1, y + rowHeight - 2 };
2314 //width -= EXTRA_SPACE;
2316 if(!field.prev) width -= indent;
2319 dataDisplayFlags.firstField = field.prev ? false : true;
2321 if(!dataDisplayFlags.firstField && !dataDisplayFlags.fullRow)
2323 background = this.background;
2324 foreground = this.foreground;
2327 if(!isActive && dataDisplayFlags.selected && style.alwaysEdit && field.editable && opacity)
2330 surface.SetBackground(background);
2331 surface.Area(x-3, y, x+width-1, y + rowHeight-2);
2334 clip.left = x - EXTRA_SPACE / 2+1;
2336 clip.right = x + width - EXTRA_SPACE/2 - 0;
2337 clip.bottom = y + rowHeight - 1;
2338 surface.Clip(&clip);
2340 for(index = 0, cell = row.cells.first; cell && index != field.index; index++, cell = cell.next);
2341 // Should always be as many cells in the row as fields in the listbox
2342 if(cell && cell.isSet && field.dataType)
2345 surface.TextFont(boldFont);
2347 surface.TextFont(font);
2349 surface.SetForeground(foreground);
2350 surface.SetBackground(background);
2352 if(field.dataType.type == noHeadClass || field.dataType.type == normalClass)
2353 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);
2355 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);
2358 if(!isActive && dataDisplayFlags.selected && style.alwaysEdit && field.editable)
2359 background = formColor;
2361 if(!dataDisplayFlags.firstField && !dataDisplayFlags.fullRow)
2363 background = formColor;
2364 foreground = this.background;
2367 x += width;// + EXTRA_SPACE;
2369 if(row.header) break;
2375 int plusIndent = (style.treeBranch) ? (indent - 20 + 4) : indent;
2377 if(row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)))
2379 surface.SetForeground(row.header ? headerCollapseForeground : this.foreground);
2380 surface.Rectangle(collapseRowStart + 3 + plusIndent, y + PLUSY, collapseRowStart + 11 + plusIndent, y + PLUSY + 8);
2382 surface.SetBackground(row.header ? (formColor) : (this.background)); //white
2383 surface.Area(collapseRowStart + 4 + plusIndent, y + PLUSY + 1, collapseRowStart + 10 + plusIndent, y + PLUSY + 7);
2385 surface.HLine(collapseRowStart + 5 + plusIndent, collapseRowStart + 9 + plusIndent, y+PLUSY+4);
2387 surface.VLine(y + PLUSY + 2, y + PLUSY + 6, collapseRowStart + 7 + plusIndent);
2392 // Draw the current row stipple
2393 if(style.fullRowSelect && !(style.alwaysEdit) && (dataDisplayFlags.current) && isActive)
2398 surface.LineStipple(0x5555);
2399 if(dataDisplayFlags.selected)
2400 surface.SetForeground(stippleColor);
2402 surface.SetForeground(this.foreground);
2405 surface.SetForeground(selectionColor ? selectionColor : SELECTION_COLOR);
2406 surface.Rectangle(0, y, clientSize.w-1, (y + rowHeight) - 1);
2407 surface.LineStipple(0);
2411 if(y >= clientSize.h)
2414 if(firstRowShown) surface.Clip(null);
2415 if(this.dragRow && this.dropIndex != -1)
2417 int dropIndex = this.dropIndex;
2420 if(!style.multiSelect && currentRow.index < this.dropIndex)
2422 surface.DrawingChar(223);
2424 y = style.header ? rowHeight : 0;
2425 y += dropIndex * rowHeight - scroll.y;
2427 surface.SetForeground(Color { 85, 85, 255 });
2428 surface.HLine(0, clientSize.w-1, y);
2429 surface.HLine(0, clientSize.w-1, y + 1);
2433 void OnDrawOverChildren(Surface surface)
2435 if(draggingField && this.dropField)
2437 int position = this.dropField.x;
2438 if(draggingField.x < position)
2439 position += this.dropField.width + EXTRA_SPACE;
2441 surface.SetForeground(Color { 85, 85, 255 });
2442 surface.VLine(0, rowHeight - 1, position - scroll.x - 2);
2443 surface.VLine(0, rowHeight - 1, position - scroll.x);
2445 if(sortField && !style.clearHeader && style.header)
2447 DataField field = sortField;
2448 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2449 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2452 surface.TextExtent(field.header, strlen(field.header), &tw, &th);
2453 if(tw < width - EXTRA_SPACE)
2455 bool up = field.sortOrder == 1;
2459 field.x + 2 - scroll.x, 0,
2460 field.x + width + EXTRA_SPACE - 1 - scroll.x, rowHeight
2462 surface.Clip(&clip);
2463 if(field.alignment == left || field.alignment == center)
2465 if(field.alignment == center)
2466 x = field.x + (width + EXTRA_SPACE - tw) / 2 + tw + EXTRA_SPACE + 4;
2468 x = field.x + tw + EXTRA_SPACE + 4;
2470 x = Min(x, field.x + width - 4);
2472 else if(field.alignment == right)
2474 x = field.x + width - tw - EXTRA_SPACE - 4;
2475 x = Max(x, field.x + 2);
2481 // surface.SetForeground((wmenu.selectedFlag == item) ? white : black);
2482 // surface.WriteText(clientSize.w-8, y+(wmenu.rh - 8)/2, "\020", 1);
2488 surface.SetForeground(Color { 128,128,128 } );
2489 surface.DrawLine(x + 3, y, x, y + 5);
2490 surface.PutPixel(x + 1, y + 5);
2491 surface.PutPixel(x + 1, y + 3);
2492 surface.PutPixel(x + 2, y + 1);
2494 surface.SetForeground(white);
2495 surface.DrawLine(x + 4, y, x + 7, y + 5);
2496 surface.PutPixel(x + 6, y + 5);
2497 surface.PutPixel(x + 6, y + 3);
2498 surface.PutPixel(x + 5, y + 1);
2500 surface.DrawLine(x, y + 6, x + 7, y + 6);
2504 surface.SetForeground(Color { 128,128,128 });
2505 surface.DrawLine(x + 3, y+6, x, y+1);
2506 surface.PutPixel(x + 1, y+1);
2507 surface.PutPixel(x + 1, y+3);
2508 surface.PutPixel(x + 2, y+5);
2510 surface.SetForeground(white);
2511 surface.DrawLine(x + 4, y+6, x + 7, y+1);
2512 surface.PutPixel(x + 6, y+1);
2513 surface.PutPixel(x + 6, y+3);
2514 surface.PutPixel(x + 5, y+5);
2516 surface.DrawLine(x, y, x + 7, y);
2525 void OnResize(int w, int h)
2528 bool showEndBevel = false;
2530 if(style.collapse && !style.treeBranch)
2532 for(field = fields.first; field; field = field.next)
2534 int width = field.width + EXTRA_SPACE;
2542 (rowCount * rowHeight) +
2543 ((style.header) ? rowHeight : 0) -
2544 ((!((clientSize.h+1) % rowHeight)) ? rowHeight : 0), true);
2546 for(field = fields.first; field; field = field.next)
2548 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2549 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2550 if(style.header && field.headButton)
2552 showEndBevel = true;
2555 field.headButton.position = { field.x, 0 };
2556 field.headButton.size = { width, rowHeight };
2557 field.headButton.visible = true;
2560 field.headButton.visible = false;
2564 if(!style.fillLastField && showEndBevel && endBevel)
2566 endBevel.position = { x, 0 };
2567 endBevel.size = { clientSize.w + 2 - x, rowHeight };
2568 endBevel.visible = true;
2571 endBevel.visible = false;
2573 if(style.alwaysEdit && editData && editData.visible)
2575 HideEditBox(true, false, true);
2579 void AdaptToFieldWidth(DataField field, bool doScroll)
2581 OnResize(clientSize.w, clientSize.h);
2583 // Scroll appropriately
2586 if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x &&
2587 field.x >= field.x + field.width + EXTRA_SPACE - clientSize.w)
2589 SetScrollPosition(field.x + field.width + EXTRA_SPACE - clientSize.w, scroll.y);
2591 else if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x ||
2593 SetScrollPosition(field.x, scroll.y);
2598 bool HeaderPushed(Button control, int x, int y, Modifiers mods)
2600 DataField field = (DataField)control.id;
2601 // false: dont destroy edit box
2602 HideEditBox(true, false, true);
2603 if(style.resizable && ((!field && x < RESIZE_BORDER && fields.last) ||
2604 (field && x < RESIZE_BORDER && field.prev) ||
2605 (field && x >= control.clientSize.w - RESIZE_BORDER)))
2608 field = fields.last;
2609 else if(x < RESIZE_BORDER && field.prev)
2612 resizingField = field;
2613 this.resizeX = x + control.position.x;
2614 this.startWidth = field.width;
2615 this.oldX = x - scroll.x;
2620 draggingField = field;
2621 if(style.moveFields)
2622 field.headButton.stayDown = true;
2623 else if(!style.sortable)
2631 bool HeaderMouseMove(Button control, int x, int y, Modifiers mods)
2636 DataField field = resizingField;
2638 x += control.position.x;
2640 // Tweak to prevent shrinking field if we're actually moving right
2641 if(x - scroll.x > this.oldX &&
2642 this.startWidth + x - this.resizeX < field.width)
2644 this.oldX = x - scroll.x;
2647 this.oldX = x - scroll.x;
2649 field.width = this.startWidth + x - this.resizeX;
2650 field.width = Max(field.width, - EXTRA_SPACE);
2652 AdaptToFieldWidth(field, true);
2654 else if(draggingField)
2656 x += control.position.x;
2657 if(style.moveFields)
2659 DataField field = fields.last;
2661 for(field = fields.first; field; field = field.next)
2663 fieldX += ((field.width || style.resizable) ?
2664 field.width : clientSize.w) + EXTRA_SPACE;
2668 if(draggingField == field)
2670 // Reset scroll position
2671 if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x &&
2672 field.x >= field.x + field.width + EXTRA_SPACE - clientSize.w)
2675 field.x + field.width + EXTRA_SPACE - clientSize.w,
2678 else if(field.x + field.width + EXTRA_SPACE - clientSize.w > scroll.x ||
2680 SetScrollPosition(field.x, scroll.y);
2683 if(this.dropField != field)
2685 this.dropField = field;
2688 int position = field.x;
2690 if(draggingField.x < position)
2692 position += field.width + EXTRA_SPACE - clientSize.w;
2693 if(position > scroll.x)
2694 SetScrollPosition(position, scroll.y);
2699 if(position < scroll.x)
2700 SetScrollPosition(position, scroll.y);
2703 this.movingFields = true;
2709 else if(style.resizable)
2711 DataField field = (DataField)control.id;
2714 if(x < RESIZE_BORDER && field.prev)
2715 control.cursor = guiApp.GetCursor(sizeWE);
2716 else if(x >= control.clientSize.w - RESIZE_BORDER)
2717 control.cursor = guiApp.GetCursor(sizeWE);
2719 control.cursor = null;
2723 if(x < RESIZE_BORDER && fields.last)
2724 control.cursor = guiApp.GetCursor(sizeWE);
2726 control.cursor = null;
2732 bool HeaderReleased(Button control, int x, int y, Modifiers mods)
2736 NotifyResized(master, this, resizingField, mods);
2737 resizingField = null;
2744 if(style.moveFields)
2749 DataField switchField = fields.last;
2753 x += draggingField.x;
2754 for(field = fields.first; field; field = field.next)
2756 fieldX += ((field.width || style.resizable) ?
2757 field.width : clientSize.w) + EXTRA_SPACE;
2760 switchField = field;
2764 if(switchField && draggingField != switchField && this.dropField)
2766 for(field = fields.first; field; field = field.next)
2768 if(field == switchField || field == draggingField)
2772 // Switch field first: move before
2773 if(field == switchField)
2774 draggingField.Move(switchField.prev);
2775 // Dragged field first: move after
2777 draggingField.Move(switchField);
2779 NotifyMovedField(master, this, draggingField, mods);
2781 draggingField.headButton.stayDown = false;
2786 movingFields = false;
2788 draggingField = null;
2794 bool HeaderClicked(Button control, int x, int y, Modifiers mods)
2796 if(style.header && !this.dropField && style.sortable)
2798 DataField field = (DataField)control.id;
2799 if(sortField == field)
2800 field.sortOrder *= -1;
2805 Sort(sortField, field.sortOrder);
2806 NotifySort(master, this, field, mods);
2814 if(style.freeSelect)
2819 this.rolledOver = this.dragging = false;
2826 bool OnLoadGraphics()
2828 display.FontExtent(fontObject, "W", 1, null, &fontH);
2829 if(!style.heightSet)
2831 rowHeight = Max(fontH + 2, 16) + (style.alwaysEdit ? 1 : 0);
2832 SetScrollLineStep(8, rowHeight);
2837 void OnApplyGraphics()
2839 SetScrollLineStep(8, rowHeight);
2843 for(field = fields.first; field; field = field.next)
2845 if(field.headButton)
2847 field.headButton.bevel = (!guiApp.textMode && !style.clearHeader);
2849 field.headButton.background = Color { 0, 170, 0 };
2853 OnResize(clientSize.w, clientSize.h);
2856 bool OnResizing(int *w, int *h)
2860 if(!initSize.w && (!anchor.left.type || !anchor.right.type) /**w*/)
2865 Font font = fontObject;
2866 Font boldFont = this.boldFont.font;
2867 Display display = this.display;
2869 for(row = rows.first; row; row = row.GetNextRow())
2871 Bitmap icon = row.icon ? row.icon.bitmap : null;
2872 int x = -scroll.x + EXTRA_SPACE / 2-1;
2876 for(parent = row.parent; parent; parent = parent.parent)
2880 if(style.treeBranch)
2886 if(style.rootCollapse) indent += 20;
2888 if(style.collapse && !(style.treeBranch)) x += 15;
2892 // Compute the rows size
2893 for(field = fields.first; field; field = field.next)
2895 if(((style.resizable && (!(style.alwaysEdit) || field.next)) || field.width) && !row.header)
2896 x += field.width - (field.prev ? 0 : indent);
2901 for(index = 0, cell = row.cells.first; index != field.index; index++, cell = cell.next);
2903 // Should always be as many cells in the row as fields in the listbox
2904 if(cell && cell.isSet && field.dataType)
2907 char tempString[1024];
2910 if(field.dataType.type == 0 normalClass || field.dataType.type == noHeadClass)
2911 string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, cell.data[0], tempString, field.userData, null);
2913 string = (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, cell.data, tempString, field.userData, null);
2915 if(!string) string = "";
2916 display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, &th);
2919 display.FontExtent(row.header ? boldFont : font, string, strlen(string), &tw, &th);
2921 display.FontExtent(row.header ? boldFont : font, "", 0, &tw, &th);
2924 if(row.header) break;
2928 maxWidth = Max(maxWidth, x);
2934 *h = Min(this.maxShown, this.rowCount) * rowHeight;
2939 if(!*w) *w = rowHeight * 5;
2940 if(!*h) *h = rowHeight * 5;
2947 FontResource font = this.font;
2948 FontResource boldFont
2950 faceName = font.faceName, size = font.size, bold = true
2952 AddResource(boldFont);
2953 RemoveResource(this.boldFont);
2954 this.boldFont = boldFont;
2958 SetInitSize(initSize);
2961 bool OnMouseMove(int x, int y, Modifiers mods)
2963 bool isTimer = false;
2964 int realX = x, realY = y;
2966 if(insideNotifySelect) return true;
2968 if(style.alwaysEdit && style.resizable &&
2969 resizingField && !(mods.isSideEffect))
2972 DataField field = resizingField;
2973 field.width = this.startWidth + x - this.resizeX;
2974 field.width = Max(field.width, - EXTRA_SPACE);
2976 AdaptToFieldWidth(field, true);
2980 if(style.alwaysEdit && style.resizable)
2982 int vx = -scroll.x - 1;
2985 if(style.collapse && !(style.treeBranch))
2988 for(field = fields.first; field; field = field.next)
2990 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
2991 clientSize.w - field.x : (field.width + EXTRA_SPACE);
2997 cursor = guiApp.GetCursor(sizeWE);
3001 vx += width + EXTRA_SPACE;
3005 if((editData && editData.visible) || (style.alwaysEdit))
3008 if(x == MAXINT && y == MAXINT)
3015 // ADDED THIS CHECK FOR FieldDropBox LEAKS
3016 if(/*!mods.isSideEffect && */(this.rolledOver || !this.dragging))
3018 int rowY = (style.header) ? rowHeight : 0;
3026 ((vertScroll && vertScroll.visible &&
3027 (y < 0 || y >= clientSize.h)) ||
3028 (horzScroll && horzScroll.visible &&
3029 (x < 0 || x >= clientSize.w))))
3034 if(vertScroll && vertScroll.visible &&
3035 (y < 0 || y >= clientSize.h))
3036 vertScroll.Action((y<0)?up:down, 0, 0);
3037 if(horzScroll && horzScroll.visible &&
3038 (x < 0 || x >= clientSize.w))
3039 horzScroll.Action((x<0)?up:down, 0, 0);
3045 // This must be done after the scrolling took place
3046 rowIndex = firstRowShown ? firstRowShown.index : -1;
3048 y = Min(y, clientSize.h-1);
3049 for(row = firstRowShown; row; row = row.GetNextRow(), rowIndex ++)
3058 if(row && currentRow != row)
3060 if(this.dragRow && style.moveRows)
3062 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
3064 else if(style.multiSelect)
3067 for(thisRow = rows.first; thisRow; thisRow = thisRow.GetNextRow())
3068 if((thisRow.selectedFlag == selected || thisRow.selectedFlag == tempSelected) ||
3074 if(this.dropIndex != rowIndex)
3076 this.dropIndex = rowIndex;
3077 this.editRow = null;
3079 this.movedRow = true;
3082 else if((style.freeSelect || this.dragging) && ((realX>= 0 && realY >= 0 && realX< clientSize.w && realY < clientSize.h) || this.rolledOver))
3084 if(!(style.multiSelect))
3086 if(currentRow)currentRow.selectedFlag = unselected;
3087 if(row)row.selectedFlag = selected;
3091 if(style.multiSelect)
3095 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3097 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3098 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3101 if(rowIndex >= clickedRow.index)
3103 for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
3105 selRow.selectedFlag = (selRow.selectedFlag == selected) ? tempUnselected : tempSelected;
3112 for(selRow = row; selRow; selRow = selRow.GetNextRow())
3114 selRow.selectedFlag = (selRow.selectedFlag == selected) ? tempUnselected : tempSelected;
3115 if(selRow == clickedRow)
3121 if(style.freeSelect)
3122 NotifyHighlight(master, this, currentRow, mods);
3125 insideNotifySelect = true;
3126 NotifySelect(master, this, currentRow, mods);
3127 insideNotifySelect = false;
3130 if(style.alwaysEdit && currentRow)
3131 currentRow.Edit(currentField);
3138 bool OnMouseOver(int x, int y, Modifiers mods)
3141 this.rolledOver = true;
3145 bool OnActivate(bool active, Window swap, bool * goOnWithActivation, bool direct)
3147 // TOCHECK: WAS THIS MISSING ? CHECK FOR SLOWDOWN
3148 if(!active) Update(null);
3150 if(!active && (!swap || !swap.isModal))
3152 // true: destroy edit box
3153 HideEditBox(true, true, false);
3155 else if(!swap || !swap.isModal)
3157 // Bring back edit box
3158 if(currentRow && style.alwaysEdit)
3160 currentRow.Edit(currentField ? currentField : null);
3164 return true; //NotifyActivate(master, this, active, swap, 0);
3168 bool OnButtonDown(int x, int y, Modifiers mods, bool right)
3171 // Check to see if we're dragging the vertical divider
3172 if(style.alwaysEdit && style.resizable && !right)
3174 int vx = -scroll.x - 1;// + EXTRA_SPACE;// / 2 - 1;
3177 if(style.collapse && !(style.treeBranch))
3180 for(field = fields.first; field; field = field.next)
3182 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3183 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3189 resizingField = field.prev;
3191 this.startWidth = resizingField.width;
3193 SetMouseRangeToClient();
3197 vx += width + EXTRA_SPACE;
3201 if(!(style.freeSelect))
3203 int rowY = (style.header) ? rowHeight : 0;
3205 int rowIndex = firstRowShown ? firstRowShown.index : -1;
3206 DataRow previousRow = currentRow;
3207 DataRow newCurrentRow = null;
3208 DataField newCurrentField = null;
3209 bool moveMultiple = false;
3210 int numSelected = 0;
3211 int rowStart = -scroll.x;
3213 if(style.multiSelect)
3220 for(row = rows.first; row; row = row.GetNextRow())
3222 if(row.selectedFlag == tempSelected)
3223 row.selectedFlag = selected;
3224 else if(row.selectedFlag == tempUnselected)
3225 row.selectedFlag = unselected;
3226 if(row.selectedFlag == selected)
3233 for(row = firstRowShown; row; row = row.GetNextRow(), rowIndex ++)
3236 if(rowY > y || (style.multiSelect && !row.GetNextRow()))
3239 if(style.treeBranch)
3242 for(parent = (style.rootCollapse) ? row.parent : (row.parent ? row.parent.parent : null); parent; parent = parent.parent)
3248 /* THIS WAS TOO STRICT:
3249 if(style.collapse && row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)) &&
3250 (x >= rowStart + 3 + plusIndent && y >= rowY - rowHeight + PLUSY && x <= rowStart + 11 + plusIndent && y <= rowY - rowHeight + PLUSY + 8))
3252 if(style.collapse &&
3253 (x >= rowStart && y >= rowY - rowHeight && x <= rowStart + 18 + plusIndent && y <= rowY + rowHeight-1))
3255 if(row.subRows.first && (row.parent || !(style.treeBranch) || (style.rootCollapse)) && x >= plusIndent)
3256 row.collapsed = !row.collapsed;
3263 newCurrentRow = row;
3265 if(style.multiSelect)
3267 // Deselect everything if user didn't clicked on a row
3271 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3272 selRow.selectedFlag = unselected;
3274 //this.clickedRowIndex = rowIndex;
3276 else if(style.moveRows && !(mods.shift) &&
3277 (row.selectedFlag == selected || row.selectedFlag == tempSelected) &&
3278 !right && !(mods.isActivate))
3279 moveMultiple = true;
3285 if(row.selectedFlag == tempUnselected || row.selectedFlag == unselected)
3287 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3288 selRow.selectedFlag = unselected;
3289 row.selectedFlag = selected;
3292 //this.clickedRowIndex = rowIndex;
3298 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3299 selRow.selectedFlag = unselected;
3303 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3305 if(selRow != clickedRow)
3307 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3308 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3315 if(rowIndex >= clickedRow.index)
3317 for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
3321 if(selRow != clickedRow)
3323 if(selRow.selectedFlag)
3324 selRow.selectedFlag = tempUnselected;
3326 selRow.selectedFlag = tempSelected;
3330 selRow.selectedFlag = selected;
3337 for(selRow = row; selRow; selRow = selRow.GetNextRow())
3341 if(selRow != clickedRow)
3343 if(selRow.selectedFlag)
3344 selRow.selectedFlag = tempUnselected;
3346 selRow.selectedFlag = tempSelected;
3350 selRow.selectedFlag = selected;
3351 if(selRow == clickedRow)
3360 if(row.selectedFlag)
3361 row.selectedFlag = tempUnselected;
3362 else row.selectedFlag = tempSelected;
3365 row.selectedFlag = tempSelected;
3367 //this.clickedRowIndex = rowIndex;
3377 // true: destroy edit box
3380 incref newCurrentRow;
3383 if(currentRow != newCurrentRow)
3384 HideEditBox(true, true, false);
3388 if(newCurrentRow._refCount <= 1)
3389 delete newCurrentRow;
3391 newCurrentRow._refCount--;
3396 if(!(style.multiSelect))
3398 if(currentRow) currentRow.selectedFlag = unselected;
3399 if(newCurrentRow) newCurrentRow.selectedFlag = selected;
3403 if(currentRow != newCurrentRow)
3406 // true: destroy edit box
3409 //incref newCurrentRow;
3410 incref newCurrentRow;
3413 HideEditBox(true, true, false);
3418 int headerSize = ((style.header) ? rowHeight : 0);
3419 int height = clientSize.h + 1 - headerSize;
3421 /*if(newCurrentRow._refCount <= 1)
3422 delete newCurrentRow;
3425 newCurrentRow._refCount--;
3426 //newCurrentRow._refCount--;
3429 currentRow = newCurrentRow;
3431 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
3432 SetScrollPosition(scroll.x,
3433 currentRow.index * rowHeight - height + rowHeight);
3434 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
3436 int line = currentRow ? currentRow.index * rowHeight : 0;
3437 //SNAPUP(line, rowHeight);
3438 SetScrollPosition(scroll.x, line);
3441 // GO THROUGH SetCurrentRow eventually?
3442 // SetCurrentRow(newCurrentRow, true);
3446 if(style.freeSelect)
3447 NotifyHighlight(master, this, currentRow, mods);
3448 else if((moveMultiple || (!(style.multiSelect) && previousRow == currentRow)) &&
3449 newCurrentRow && !(mods.shift))
3453 if(!(mods.isActivate))
3457 this.dragRow = currentRow;
3458 this.dropIndex = -1;
3459 this.movedRow = false;
3461 if(editData && editData.visible && style.alwaysEdit)
3468 if(style.collapse && !style.treeBranch)
3471 for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3473 indent += (style.treeBranch) ? 20 : 15;
3476 for(field = fields.first; field; field = field.next)
3478 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3479 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3481 if(!field.prev) width -= indent;
3482 if(x >= sx && x < sx + width)
3486 if(field == currentField)
3487 editData.Deactivate();
3490 currentRow.Edit(field);
3491 editData.Activate();
3494 else if(!(mods.ctrl) && numSelected <= 1)
3495 this.editRow = currentRow;
3497 if(style.noDragging && newCurrentRow)
3498 NotifyReclick(master, this, newCurrentRow, mods);
3502 // If the user clicked exactly on the edited field,
3504 if(editData && editData.visible && newCurrentRow)
3506 DataField field, whichField;
3510 if(style.collapse && !(style.treeBranch))
3513 whichField = currentField;
3517 for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3519 indent += (style.treeBranch) ? 20 : 15;
3523 for(field = fields.first; field; field = field.next)
3525 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3526 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3527 if(!field.prev) width -= indent;
3528 if(x >= sx && x < sx + width && newCurrentRow)
3533 if(field) //x >= sx && x < sx + width && newCurrentRow)
3535 if(field == currentField)
3536 editData.Activate();
3538 newCurrentRow.Edit(currentField);*/
3540 else if(style.noDragging && newCurrentRow)
3541 NotifyReclick(master, this, newCurrentRow, mods);
3543 else if(style.noDragging && newCurrentRow)
3544 NotifyReclick(master, this, newCurrentRow, mods);
3550 result = NotifySelect(master, this,
3551 currentRow ? currentRow : null, mods);
3552 if(result && style.alwaysEdit && currentRow)
3556 DataField field = null;
3561 if(style.collapse && !style.treeBranch)
3564 for(parent = newCurrentRow.parent; parent; parent = parent.parent)
3566 indent += (style.treeBranch) ? 20 : 15;
3569 for(field = fields.first; field; field = field.next)
3571 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3572 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3574 if(!field.prev) width -= indent;
3575 if(x >= sx && x < sx + width)
3577 currentField = field;
3583 currentRow.Edit(currentField);
3585 // If the user clicked exactly on the edited field,
3587 if(editData && editData.visible && newCurrentRow)
3591 editData.Activate();
3593 else if(style.noDragging && newCurrentRow)
3594 NotifyReclick(master, this, newCurrentRow, mods);
3597 else if(style.noDragging && newCurrentRow)
3598 NotifyReclick(master, this, newCurrentRow, mods);
3602 For drop box to capture...
3605 if(x < 0 || y < 0 || x >= clientSize.w || y >= clientSize.h)
3608 master.parent.Activate();
3617 if(!style.noDragging)
3619 this.dragging = true;
3622 if(x >= 0 && y >= 0 && x < clientSize.w && y < clientSize.h)
3623 this.rolledOver = true;
3628 this.dragging = false;
3629 OnLeftButtonUp(x, y, mods);
3634 bool OnLeftButtonDown(int x, int y, Modifiers mods)
3636 return OnButtonDown(x,y, mods, false);
3639 bool OnLeftButtonUp(int x, int y, Modifiers mods)
3641 if(resizingField && style.alwaysEdit)
3643 Window::FreeMouseRange();
3645 resizingField = null;
3648 if(dragRow || editRow)
3650 DataRow row, switchRow = rows.last;
3651 int rowY = (style.header) ? rowHeight : 0;
3652 for(row = firstRowShown; row; row = row.GetNextRow())
3661 if(this.editRow == switchRow && y >= 0)
3666 for(field = fields.first; field; field = field.next)
3668 int width = (!field.next && style.fillLastField && (!hasHorzScroll || clientSize.w - field.x > field.width + EXTRA_SPACE)) ?
3669 clientSize.w - field.x : (field.width + EXTRA_SPACE);
3672 if(fieldX > x + scroll.x)
3676 if(field && field.editable)
3678 // true: destroy edit box
3679 HideEditBox(true, true, false);
3680 PopupEditBox(field, false);
3682 else if(!style.noDragging)
3683 NotifyReclick(master, this, currentRow, mods);
3685 else if(style.moveRows && switchRow)
3687 if(this.dragRow == switchRow && this.movedRow == false)
3689 DataRow row = this.dragRow;
3693 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3694 selRow.selectedFlag = unselected;
3698 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3700 if(selRow != clickedRow)
3702 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
3703 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
3709 if(row.selectedFlag)
3710 row.selectedFlag = tempUnselected;
3711 else row.selectedFlag = tempSelected;
3714 row.selectedFlag = tempSelected;
3719 if(style.multiSelect)
3721 if(!switchRow.selectedFlag)
3723 bool foundSwitch = false;
3726 DataRow afterRow = switchRow.prev;
3727 for(row = rows.first; row; row = next)
3729 next = row.GetNextRow();
3730 if(row.selectedFlag == selected || row.selectedFlag == tempSelected)
3732 if(!foundSwitch && !after)
3735 afterRow = switchRow;
3737 if(!after || !(row.selectedFlag == selected || row.selectedFlag == tempSelected) ||
3744 else if(row == switchRow)
3751 for(row = rows.first; row; row = row.GetNextRow())
3753 if(row == switchRow || row == this.dragRow)
3757 // Switch row first: move before
3758 if(row == switchRow)
3760 if(NotifyMove(master, this, switchRow.prev, mods))
3761 dragRow.Move(switchRow.prev);
3763 // Dragged row first: move after
3766 if(NotifyMove(master, this, switchRow, mods))
3767 dragRow.Move(switchRow);
3780 if(this.dragging || style.freeSelect)
3784 this.rolledOver = this.dragging = false;
3786 if(x >= 0 && y >= 0 && x < clientSize.w && y < clientSize.h && currentRow && style.freeSelect)
3790 result = NotifySelect(master, this, currentRow, mods);
3791 if(style.alwaysEdit)
3792 currentRow.Edit(currentField);
3796 // if(!(style.freeSelect))
3802 bool OnLeftDoubleClick(int x, int y, Modifiers mods)
3804 int rowStart = -scroll.x;
3806 int rowY = (style.header) ? rowHeight : 0;
3809 OnLeftButtonUp(x,y,mods);
3810 if(style.alwaysEdit)
3812 if(!(style.collapse) || x > 15)
3813 if(editData && editData.visible)
3815 editData.Activate();
3816 NotifyDoubleClick(master, this, x, y, mods);
3820 for(row = firstRowShown; row; row = row.GetNextRow())
3823 if(rowY > y || (style.multiSelect && !row.GetNextRow()))
3825 if(style.treeBranch)
3828 for(parent = (style.rootCollapse) ? row.parent : (row.parent ? row.parent.parent : null); parent; parent = parent.parent)
3837 if((row && style.collapse && (x >= rowStart && x <= rowStart + 18 + plusIndent)) ||
3838 NotifyDoubleClick(master, this, x, y, mods))
3842 if(row && row.subRows.first)
3844 row.collapsed = !row.collapsed;
3848 // We need to return true here so that OnLeftButtonDown can popup the DataBox Editors
3854 bool OnRightButtonDown(int x, int y, Modifiers mods)
3856 return OnButtonDown(x,y, mods, true);
3859 bool OnRightButtonUp(int x, int y, Modifiers mods)
3861 OnLeftButtonUp(x,y,mods);
3862 return NotifyRightClick(master, this, x, y, mods);
3865 bool GoToLetter(unichar ch, bool keyHit)
3867 bool result = false;
3869 bool checkNextField = true;
3870 int len = keyHit ? 0 : strlen(typedString);
3872 typedString = renew typedString char[len + 2];
3873 typedString[len++] = (char)tolower(ch); // TODO: FIX UNICODE
3874 typedString[len] = '\0';
3876 for(field = fields.first; field; field = field.next)
3878 DataRow startRow = currentRow ? currentRow : rows.first;
3880 if(startRow && field.dataType && field.dataType._vTbl[__ecereVMethodID_class_OnGetString] && ch)
3883 bool looped = false;
3884 if(len == 1 && currentRow)
3885 startRow = (next = startRow.GetNextRow(), (next ? next : rows.first));
3887 for(row = startRow; row != startRow || !looped; next = row.GetNextRow(), row = next ? next : rows.first)
3889 void * data = row.GetData(field);
3890 char tempString[1024] = "";
3891 bool needClass = false;
3892 char * string = data ? (char *)field.dataType._vTbl[__ecereVMethodID_class_OnGetString](field.dataType, data, tempString, null, &needClass) : null;
3894 if(string && string[0])
3895 checkNextField = false;
3896 if(string && string[0] && !strnicmp(string, typedString, len))
3898 if(style.multiSelect)
3901 bool foundRow = false;
3903 //this.clickedRowIndex = 0;
3905 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
3907 if(selRow == row) foundRow = true;
3908 selRow.selectedFlag = unselected;
3909 //if(!foundRow) this.clickedRowIndex++;
3911 row.selectedFlag = selected;
3913 SetCurrentRow(row, true);
3920 if(this.typingTimeOut && !keyHit)
3921 typingTimer.Start();
3922 if(!result || !this.typingTimeOut || keyHit)
3923 typedString[len-1] = '\0';
3925 if(!checkNextField || result) break;
3930 bool OnKeyDown(Key key, unichar ch)
3934 if(key == enter || key == keyPadEnter)
3936 if(editData && editData.visible && editData.active)
3938 HideEditBox(true, false, false);
3942 else if(key == escape)
3944 if(resizingField || this.movingFields || (editData && editData.visible) || this.dragRow)
3946 if(editData && editData.visible && style.alwaysEdit && !editData.active)
3948 // false: dont destroy edit box
3949 HideEditBox(false, false, false);
3952 resizingField.width = this.startWidth;
3953 AdaptToFieldWidth(resizingField, true);
3954 resizingField = null;
3957 this.dragRow = null;
3960 this.dragging = false;
3964 this.movingFields = false;
3965 draggingField = null;
3971 if(!currentField || !currentField.editable)
3972 for(field = fields.first; field; field = field.next)
3976 currentField = field;
3980 if(key == f2 && currentField && currentField.editable)
3982 PopupEditBox(currentField, false);
3983 if(editData && editData.visible)
3985 if(style.alwaysEdit)
3986 editData.Activate();
3991 if(!NotifyKeyDown(master, this, currentRow, key, ch))
3994 // Editable fields...
3997 if(style.alwaysEdit && editData && editData.visible)
3998 return editData.OnKeyDown(key, ch);
3999 return true; // We want to pick up the OnKeyHit to replace contents, but skip GoToLetter
4002 if(ch != 128 && !key.alt && !key.ctrl && GoToLetter(ch, false))
4004 /*if(inactive && window.state != Hidden)
4005 NotifyHighlight(master, this, currentRow, 0);
4008 NotifySelect(master, this, currentRow, 0);
4015 bool OnKeyHit(Key key, unichar ch)
4017 if(key.code == up && key.alt == true && key.ctrl == false && key.shift == false)
4020 if(!ch && !key.alt && !key.ctrl)
4022 key.code = (SmartKey)key.code;
4024 if(ch >= 32 && !key.alt && !key.ctrl && ch != 128)
4027 if(!currentField || !currentField.editable)
4028 for(field = fields.first; field; field = field.next)
4032 currentField = field;
4036 if(currentField && currentField.editable)
4038 if((!editData || !editData.visible) || !editData.active)
4040 PopupEditBox(currentField, false);
4041 if(editData && editData.visible)
4043 editData.Activate();
4044 editData.OnKeyHit(key, ch);
4051 if(!(style.multiSelect) && (key.ctrl))
4054 if(editData && editData.visible && ch && !key.alt && !key.ctrl && editData.active)
4060 if(style.alwaysEdit)
4065 for(field = currentField.prev; field; field = field.prev)
4069 currentField = field;
4070 HideEditBox(true, true, false);
4071 PopupEditBox(currentField, false);
4077 if(style.collapse && currentRow /*&& !currentField*/) // THIS PREVENTED COLLAPSING THE PROPERTY SHEET
4079 if(currentRow.subRows.first && !currentRow.collapsed)
4081 currentRow.collapsed = true;
4083 else if(currentRow.parent)
4084 SetCurrentRow(currentRow.parent, true);
4089 if(style.collapse && currentRow && currentRow.subRows.first)
4091 if(currentRow.collapsed)
4092 currentRow.collapsed = false;
4094 SetCurrentRow(currentRow.subRows.first, true);
4097 else if(style.alwaysEdit)
4102 for(field = currentField.next; field; field = field.next)
4106 currentField = field;
4107 HideEditBox(true, true, false);
4108 PopupEditBox(currentField, false);
4116 case pageDown: case pageUp:
4117 case end: case home:
4119 int headerSize = ((style.header) ? rowHeight : 0);
4120 int height = clientSize.h + 1 - headerSize;
4123 // true: destroy edit box
4124 // !!! TESTING true HERE !!!
4125 HideEditBox(true, true, false);
4126 // HideEditBox(false, true, false);
4128 oldRow = currentRow;
4130 SNAPDOWN(height, rowHeight);
4131 if((!currentRow || key.code == home) && key.code != end)
4133 currentRow = rows.first;
4141 if(!(style.multiSelect) && currentRow && !currentRow.selectedFlag)
4144 next = currentRow.GetNextRow();
4151 if(!(style.multiSelect) && currentRow && !currentRow.selectedFlag)
4154 next = currentRow.GetPrevRow();
4162 // TODO: Find very last row
4163 for(currentRow = rows.last; currentRow && !currentRow.collapsed && currentRow.subRows.last;)
4164 currentRow = currentRow.subRows.last;
4170 currentRow && (next = currentRow.GetPrevRow()) && c < height / rowHeight;
4171 c++, currentRow = next);
4178 currentRow && (next = currentRow.GetNextRow()) && c < height / rowHeight;
4179 c++, currentRow = next);
4184 if(currentRow && currentRow.index * rowHeight > scroll.y + height - rowHeight)
4185 SetScrollPosition(scroll.x, currentRow.index * rowHeight - height + rowHeight);
4186 else if(!currentRow || currentRow.index * rowHeight < scroll.y)
4187 SetScrollPosition(scroll.x, currentRow ? currentRow.index * rowHeight : 0);
4189 if(style.multiSelect)
4193 if(!(key.shift) && (key.ctrl))
4196 for(row = rows.first; row; row = row.GetNextRow())
4198 if(row.selectedFlag == tempSelected)
4199 row.selectedFlag = selected;
4200 else if(row.selectedFlag == tempUnselected)
4201 row.selectedFlag = unselected;
4207 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4208 selRow.selectedFlag = unselected;
4212 for(selRow = rows.first; selRow; selRow = selRow.GetNextRow())
4214 if(selRow.selectedFlag == tempUnselected) selRow.selectedFlag = selected;
4215 else if(selRow.selectedFlag == tempSelected) selRow.selectedFlag = unselected;
4221 if(currentRow.index >= clickedRow.index)
4223 for(selRow = clickedRow; selRow; selRow = selRow.GetNextRow())
4227 if(selRow.selectedFlag) selRow.selectedFlag = tempUnselected; else selRow.selectedFlag = tempSelected;
4230 selRow.selectedFlag = selected;
4231 if(selRow == currentRow)
4237 for(selRow = currentRow; selRow; selRow = selRow.GetNextRow())
4241 if(selRow.selectedFlag) selRow.selectedFlag = tempUnselected; else selRow.selectedFlag = tempSelected;
4244 selRow.selectedFlag = selected;
4245 if(selRow == clickedRow)
4252 if(!(key.ctrl) && currentRow)
4254 currentRow.selectedFlag = selected;
4257 clickedRow = currentRow;
4262 if(oldRow) oldRow.selectedFlag = unselected;
4263 if(currentRow) currentRow.selectedFlag = selected;
4268 if(style.freeSelect)
4269 NotifyHighlight(master, this, currentRow, 0);
4271 NotifySelect(master, this, currentRow, 0);
4273 if(style.alwaysEdit && currentRow)
4274 currentRow.Edit(currentField /*null*/);
4281 if(style.multiSelect && currentRow)
4283 if(currentRow.selectedFlag)
4286 currentRow.selectedFlag = unselected;
4289 currentRow.selectedFlag = selected;
4292 if(style.freeSelect)
4293 NotifyHighlight(master, this, currentRow, 0);
4295 NotifySelect(master, this, currentRow, 0);
4301 if(!NotifyKeyHit(master, this, currentRow, key, ch))
4304 if(ch != 128 && !key.alt && !key.ctrl && GoToLetter(ch, true))
4306 /*if(inactive && window.state != Hidden)
4307 return NotifyHighlight(master, this, currentRow, 0);
4310 return NotifySelect(master, this, currentRow, 0);
4318 void OnHScroll(ScrollBarAction action, int position, Key key)
4323 void OnVScroll(ScrollBarAction action, int position, Key key)
4328 for(firstRowShown = rows.first; firstRowShown; firstRowShown = next)
4330 next = firstRowShown.GetNextRow();
4331 if(y >= position || !next) break;
4341 DataRow firstRowShown;
4345 DataField sortField;
4349 double typingTimeOut;
4362 if(guiApp.GetKeyState(shift)) mods.shift = true;
4363 if(guiApp.GetKeyState(alt)) mods.alt = true;
4364 if(guiApp.GetKeyState(control)) mods.ctrl = true;
4365 OnMouseMove(MAXINT, MAXINT, mods);
4373 delay = 0.5; // typingTimeOut
4378 typedString[0] = '\0';
4380 // The next line was commented... Why? When commented typing words stops working ( only first character jumps )
4386 bool dragging, rolledOver;
4395 // For editing fields
4397 DataField currentField;
4400 // For moving fields
4401 DataField draggingField, dropField;
4404 // For resizing fields
4405 DataField resizingField;
4406 int resizeX, oldX, startWidth;
4409 FontResource boldFont;
4412 // Only used for OnMouseMove so far, for avoiding problems with consequential mouse moves
4413 bool insideNotifySelect;
4414 Color selectionColor, selectionText, stippleColor;
4415 stippleColor = 0xFFFFFF80;