3 define sgs = 3; // screen sgs size
7 extern int __ecereVMethodID_class_OnFree;
8 extern int __ecereVMethodID_class_OnGetString;
11 char * defaultNameField = "Name";
12 char * defaultIdField = "Id";
13 char * defaultActiveField = "Active";
15 public void SetDefaultIdField(char * value) { defaultIdField = value; }
16 public void SetDefaultNameField(char * value) { defaultNameField = value; }
18 public class ButtonStyle : Button
20 font = { $"Arial", 10, bold = true };
21 creationActivation = doNothing;
24 public class Group : Window
28 //inactive = true; // TOFIX causes problems...
31 Label title { this, font = { $"Arial", 10, bold = true }, position = { 16, 2 } };
35 title.labeledWindow = this;
39 void OnRedraw(Surface surface)
41 int x = clientSize.w - 1, y = clientSize.h - 1;
43 surface.SetBackground(gray);
45 surface.Rectangle(0, 10, x - shadowS, y - shadowS);
46 surface.Area(shadowS / 2, y - shadowS + 1, x, y);
47 surface.Area(x - shadowS + 1, 10 + shadowS / 2, x, y);
49 surface.SetBackground(white);
51 surface.Rectangle(10, 0, title.size.w + 22, title.size.h + 4);
52 surface.Area(11, 1, title.size.w + 21, title.size.h + 3);
56 public class CheckBool : bool
58 Window OnEdit(DataBox dataBox, DataBox obsolete, int x, int y, int w, int h, void * userData)
60 Button button = dataBox.keepEditor ? (Button)obsolete : null;
65 dataBox, borderStyle = 0, text = dataBox.text, anchor = { 0, 0, 0, 0 },
66 // size = { 100, 22 };
67 modifyVirtualArea = false, isCheckbox = true;
69 bool DataBox::NotifyClicked(Button control, int x, int y, Modifiers mods)
71 bool checked = control.checked;
73 control.checked = !checked;
75 SetData(&checked, false);
80 button.checked = this;
86 String GetNameString(Row r, Field nameField)
89 if(nameField.type != class(String) && nameField.type != class(char *))
91 char tempString[4096];
92 Class type = nameField.type;
94 if(type.type == structClass)
95 data = (int64)new0 byte[type.structSize];
96 ((bool (*)())(void *)r.GetData)(r, nameField, type, (type.type == structClass) ? (void *)data : &data);
97 s = CopyString(((char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, (void *)data, tempString, null, null));
98 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, (void *)data);
99 if(type.type == structClass)
101 void * _data = (void *)data;
106 r.GetData(nameField, s);
110 public class TableDropBox : DropBox
112 anchor = { left = 130, top = 180, right = shadowS + sgs * 2 };
130 get { return filter; }
132 property Field nameField { set { nameField = value; } }
133 property uint exclusion { set { exclusion = value; } }
134 property Table table { set { table = value; if(!nameField && value) nameField = value.FindField(defaultNameField); } }
136 virtual void Refill()
141 Field fldId = table.FindField(defaultIdField);
142 if(fldId && nameField)
145 if(filterField && filtered)
147 if(eClass_IsDerived(filterField.type, class(Id)))
149 FieldIndex indexedFields[1];
150 // Table tbl = table.db.OpenTable(table.name, { tableRows });
151 char * name = table.name;
152 Database db = table.db;
153 Table tbl = db.OpenTable(name, { tableRows });
158 indexedFields[0] = { filterField };
159 tbl.GenerateIndex(1, indexedFields, false);
163 for(r.Find(filterField, middle, nil, filter); !r.nil; r.Next()) //while(r.Next())
167 r.GetData(filterField, idFilter);
168 r.GetData(fldId, id);
169 if(idFilter != filter)
171 if(!exclusion || id != exclusion)
173 String s = GetNameString(r, nameField);
174 AddString(s).tag = id;
180 else if(eClass_IsDerived(filterField.type, class(IdList)))
186 r.GetData(filterField, idList);
187 r.GetData(fldId, id);
188 if(idList && idList.Includes(filter) && (!exclusion || !idList.Includes(exclusion)))
190 String s = GetNameString(r, nameField);
191 AddString(s).tag = id;
203 r.GetData(fldId, id);
206 String s = GetNameString(r, nameField);
207 AddString(s).tag = id;
217 String s = GetNameString(r, nameField);
218 r.GetData(fldId, id);
219 AddString(s).tag = id;
229 property Field filterField { set { filterField = value; } }
231 bool OnKeyHit(Key key, unichar ch)
233 if((SmartKey)key == del)
235 SelectRow(null); //currentRow = null;
238 else if((SmartKey)key == enter)
239 parent.CycleChildren(true, false, false, true);
241 return DropBox::OnKeyHit(key, ch);
244 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
246 modifiedDocument = true;
256 void EditNotifyCharsAdded()
258 if(!editBox.NotifyUpdate || editBox.NotifyUpdate == EditBox::NotifyUpdate)
259 editBox.NotifyUpdate = EditNotifyUpdate;
262 void EditNotifyUpdate(EditBox editBox)
265 char * contents = editBox.contents;
266 int len = strlen(contents);
267 if(len && editBox.charPos == len)
269 EditLine line = editBox.firstLine;
272 editBox.GetSelPos(null, null, &x1, null, null, &x2, false);
275 for(row = firstRow; row; row = row.next)
277 char * string = row.string;
278 if(string && SearchString(string, 0, contents, false, false) == string)
281 editBox.contents = row.string;
282 editBox.SetSelPos(line, 0, len, line, 0, strlen(string));
288 editBox.NotifyUpdate = null;
292 public class DropDataBox : DataBox
297 showNone = false; //true;
301 property uint filter { set { filtered = true; filter = value; } get { return filter; } }
302 property bool filtered { set { filtered = value; } }
303 property uint exclusion { set { exclusion = value; } }
304 property Field filterField { set { filterField = value; } }
305 property Field nameField { set { nameField = value; } }
306 virtual void TableDropBox::RefillFunction();
307 property bool showNone { set { showNone = value; } }
313 TableDropBox dropBox = (TableDropBox) editor;
314 uint id = data ? *(uint *)data : MAXDWORD;
315 void * notifyChanged = (void *)NotifyChanged;
317 OnConfigure(dropBox);
319 NotifyChanged = null;
321 NotifyChanged = notifyChanged;
323 if(id != MAXDWORD) dropBox.SelectRow(dropBox.FindSubRow(id));
327 void OnConfigure(TableDropBox dropBox)
329 if(RefillFunction != DropDataBox::RefillFunction) dropBox.Refill = RefillFunction;
330 if(nameField) dropBox.nameField = nameField;
331 if(filterField) dropBox.filterField = filterField;
333 dropBox.filter = filter;
335 dropBox.filtered = false;
337 dropBox.exclusion = exclusion;
338 dropBox.showNone = showNone;
350 public class EditDropDataBox : DropDataBox
352 void OnConfigure(TableDropBox dropBox)
354 DropDataBox::OnConfigure(dropBox);
355 dropBox.editText = true;
356 dropBox.editBox.NotifyCharsAdded = (void *)TableDropBox::EditNotifyCharsAdded;
360 public class FieldDataBox : DataBox
363 anchor = { left = 110, right = shadowS + sgs * 2 };
372 property EditSection editor
376 parent = value.editArea;
378 value.AddFieldEditor(this);
388 if(field) type = null;
392 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, (void *)dataHolder);
393 if(type.type == structClass)
395 void * dataPtr = (void *)dataHolder;
402 dataType = value ? value.type : null;
404 text = field ? field.name : null;
406 if(dataType && dataType.type == structClass)
408 dataHolder = (int64)new0 byte[dataType.structSize];
409 data = (void *)dataHolder;
411 else if(dataType && (dataType.type == noHeadClass || dataType.type == normalClass))
413 if(eClass_IsDerived(dataType, class(String)))
414 dataHolder = (int64)CopyString("");
416 dataHolder = (int64)eInstance_New(dataType);
417 data = (void *)&dataHolder;
424 if(!type) type = dataType;
431 SetData(null, false);
433 if(type && (type.type == noHeadClass || type.type == normalClass))
435 if(eClass_IsDerived(type, class(String)))
436 dataHolder = (int64)CopyString("");
438 dataHolder = (int64)eInstance_New(type);
439 data = (void *)&dataHolder;
450 SetData(null, false);
451 master.modifiedDocument = false;
453 ((bool (*)())(void *)Row::GetData)(row, field, field.type, data);
455 if(!dataHolder && type && (type.type == noHeadClass || type.type == normalClass))
457 if(eClass_IsDerived(type, class(String)))
458 dataHolder = (int64)CopyString("");
460 dataHolder = (int64)eInstance_New(type);
461 data = (void *)&dataHolder;
474 Class type = field.type;
475 if(!DataBox::SaveData())
478 ((bool (*)())(void *)Row::SetData)(row, field, type,
479 (type.type == noHeadClass || type.type == normalClass) ? *(void **)data : data);
489 bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
493 if(modifiedDocument && !DataBox::SaveData())
499 bool OnKeyDown(Key key, unichar ch)
501 if((SmartKey)key == enter)
503 DataBox::OnKeyDown(key, ch);
507 return DataBox::OnKeyDown(key, ch);
510 bool OnKeyHit(Key key, unichar ch)
512 if((SmartKey)key == enter)
513 parent.CycleChildren(true, false, false, true);
515 return DataBox::OnKeyHit(key, ch);
518 bool Window::NotifyChanged(DataBox dataBox, bool closingDropDown)
520 modifiedDocument = true;
524 bool Window::NotifyModified()
526 modifiedDocument = true;
533 SetData(null, false);
537 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, (void *)dataHolder);
538 if(type.type == structClass)
540 void * dataPtr = (void *)dataHolder;
549 int64 dataHolder; // THERE SEEMS(ED?) TO BE A BUG WHEN ACCESSING row ACROSS .so
553 public class FieldCheckButton : FieldDataBox
556 type = class(CheckBool);
557 // TOCHECK: When not here, the virtual area goes wild (anchor.right is not reset)
561 public class FieldDropDataBox : FieldDataBox
568 property uint filter { set { filtered = true; filter = value; } get { return filter; } }
569 property bool filtered { set { filtered = value; } }
570 property uint exclusion { set { exclusion = value; } }
571 property Field filterField { set { filterField = value; } }
572 property Field nameField { set { nameField = value; } }
573 virtual void TableDropBox::RefillFunction();
574 property bool showNone { set { showNone = value; } }
580 TableDropBox dropBox = (TableDropBox) editor;
581 uint id = data ? *(uint *)data : MAXDWORD;
582 OnConfigure(dropBox);
584 if(id != MAXDWORD) dropBox.SelectRow(dropBox.FindSubRow(id));
588 void OnConfigure(TableDropBox dropBox)
590 if(RefillFunction != FieldDropDataBox::RefillFunction) dropBox.Refill = RefillFunction;
591 if(nameField) dropBox.nameField = nameField;
592 if(filterField) dropBox.filterField = filterField;
594 dropBox.filter = filter;
596 dropBox.filtered = false;
597 dropBox.exclusion = exclusion;
598 dropBox.showNone = showNone;
610 public class EditFieldDropDataBox : FieldDropDataBox
614 void OnConfigure(TableDropBox dropBox)
616 FieldDropDataBox::OnConfigure(dropBox);
617 dropBox.editText = true;
618 dropBox.editBox.NotifyCharsAdded = (void *)TableDropBox::EditNotifyCharsAdded;
623 TableDropBox dropBox = (TableDropBox) editor;
625 if(!dropBox.currentRow && dropBox.contents[0])
627 Row row { dropBox.table };
629 OnAddTextEntry(row, dropBox, dropBox.contents);
634 dropBox.SelectRow(dropBox.FindSubRow(sysID));
636 FieldDataBox::Save();
639 virtual bool OnAddTextEntry(Row row, TableDropBox dropBox, char * entry)
642 row.SetData(dropBox.nameField, entry);
647 public class ListSection : Group
651 anchor = { left = sgs, top = 32 + sgs * 3, bottom = 55 + sgs * 3 };
653 property EditSection editor
671 FieldIndex indexedFields[1];
673 if(!fldId) fldId = table.FindField(defaultIdField);
674 if(!fldName) fldName = table.FindField(defaultNameField);
675 if(!fldActive) fldActive = table.FindField(defaultActiveField);
677 indexedFields[0] = { fldId };
678 table.Index(1, indexedFields);
680 editor.editRow.tbl = table;
687 Field fldId, fldName, fldActive;
689 virtual DialogResult Window::NotifySaveConfirmation(ListSection listSection)
691 return MessageBox { master = this, type = yesNoCancel, text = $"List Editor", contents = $"You have modified this entry. Would you like to save it before proceeding?" }.Modal();
694 bool OnClose(bool parentClosing)
696 if(editor && editor.modifiedDocument)
698 switch(NotifySaveConfirmation(master, this))
705 editor.modifiedDocument = false;
715 //if(fldId && fldName)
718 NotifyRefillList(master, this, r);
722 editor.modifiedDocument = false;
725 virtual void Window::NotifyRefillList(ListSection listSection, Row r)
727 if(listSection.fldId && listSection.fldName)
729 bool stringName = !strcmp(listSection.fldName.type.dataTypeString, "char *");
734 r.GetData(listSection.fldId, id);
736 r.GetData(listSection.fldName, s);
738 s = PrintString("Entry ", id);
739 listSection.list.AddString(s).tag = id;
745 virtual bool Window::NotifyNew(ListSection listSection, Row r);
749 this, anchor = { right = shadowS + sgs * 2, top = 24 }, hotKey = altW, text = $"New";
751 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
753 list.NotifySelect(this, list, null, 0);
754 if(!editor.modifiedDocument)
756 uint id; // = table.rowsCount + 1; // this is bad with deleted rows, won't work, how to have unique id?
759 if(r.Last()) // this will reuse ids in cases where the item(s) with the last id have been deleted
761 r.GetData(fldId, id);
772 // Patch for SQLite driver which auto-increments IDs
774 if(r.GetData(fldId, curID))
777 r.SetData(fldId, id);
779 if(!strcmp(fldName.type.dataTypeString, "char *"))
780 r.SetData(fldName, $"[New]");
783 r.SetData(fldActive, active);
785 if(NotifyNew(master, this, r))
786 list.currentRow = list.AddString($"[New]");
791 list.currentRow.tag = id;
792 SelectListRow(list.currentRow);
799 virtual bool Window::NotifyDeleteConfirmation(ListSection listSection)
801 return MessageBox { master = this, type = yesNo, text = $"List Editor",
802 contents = $"You are about to delete an entry.\n"
803 "Do you wish to continue?"
807 virtual void Window::NotifyDeleting(ListSection listSection);
808 virtual void Window::NotifyDeleted(ListSection listSection);
810 ButtonStyle btnDelete
812 this, anchor = { right = shadowS + sgs * 2, top = 24 }, hotKey = altD, text = $"Delete";
814 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
818 if(NotifyDeleteConfirmation(master, this))
820 NotifyDeleting(master, this);
822 editor.editRow.Delete();
823 list.DeleteRow(list.currentRow);
826 NotifyDeleted(master, this);
828 SelectListRow(list.currentRow);
836 bool FilterNotifyChanged(DataBox dataBox, bool closeDropDown)
841 SelectListRow(list.firstRow);
848 this, anchor = { left = sgs * 2, top = 22 + 22 + sgs * 4, right = shadowS + sgs * 2, bottom = shadowS + sgs * 2 };
849 alwaysHighLight = true;
851 bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
854 if(/*row && */row != lastRow)
857 if(editor.modifiedDocument)
860 list.currentRow = lastRow;
862 switch(NotifySaveConfirmation(master, this))
869 editor.modifiedDocument = false;
870 list.currentRow = row;
880 virtual void Window::NotifySelectListRow(ListSection listSection, uint64 id);
882 void SelectListRow(DataRow row)
884 // Time startTime = GetTime();
890 if(list.currentRow != row)
891 list.currentRow = row;
892 if(editor.editRow.Find(fldId, middle, nil, id))
894 editor.listRow = row;
895 NotifySelectListRow(master, this, id);
899 // Logf("SelectListRow took %f seconds\n", GetTime() - startTime);
905 SelectListRow(list.firstRow);
913 editor.btnSave.disabled = !(bool)list.currentRow;
914 editor.btnReload.disabled = !(bool)list.currentRow;
915 btnDelete.disabled = !(bool)list.currentRow;
916 editor.disabled = !(bool)list.firstRow;
920 void OnResize(int width, int height)
922 int x = width - btnDelete.size.w - 20;
924 btnDelete.position.x = x;
926 btnNew.position.x = x = x - btnNew.size.w - sgs * 2;
929 bool OnPostCreate(void)
931 OnResize(clientSize.w, clientSize.h);
933 if(editor) editor.modifiedDocument = false;
934 return Window::OnPostCreate();
943 public class EditSection : Group
948 anchor = { right = sgs, top = 32 + sgs * 3, bottom = 55 + sgs * 3 };
952 editBoxes.Free(null);
973 OldList editBoxes { };
975 Window editArea { this, borderStyle = deep, tabCycle = true, anchor = { left = 8, top = 54, right = 10, bottom = 10 }, hasVertScroll = true, dontHideScroll = true };
979 this, anchor = { right = shadowS + sgs * 2, top = 24 }, hotKey = altV, text = $"Save";
981 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
988 ButtonStyle btnReload
990 this, anchor = { left = 10, top = 24 }, hotKey = altV, text = $"Revert";
992 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1000 void AddFieldEditor(FieldDataBox box)
1002 editBoxes.Add(OldLink { data = box });
1005 virtual void Window::NotifyInitFields(EditSection editSection);
1010 for(link = editBoxes.first; link; link = link.next)
1012 FieldDataBox dataBox = link.data;
1015 NotifyInitFields(master, this);
1020 modifiedDocument = false;
1023 virtual void Window::NotifyEditSave(EditSection edit, String name)
1025 edit.listRow.string = name;
1030 bool stringName = !strcmp(list.fldName.type.dataTypeString, "char *");
1034 editRow.tbl.db.Begin();
1035 for(link = editBoxes.first; link; link = link.next)
1037 FieldDataBox dataBox = link.data;
1040 editRow.tbl.db.Commit();
1041 // ADDED THIS HERE FOR SQLITE TO REFRESH
1042 editRow.Find(list.fldId, middle, nil, list.list.currentRow.tag);
1045 editRow.GetData(list.fldName, name);
1047 name = PrintString("Entry ", list.list.currentRow.tag);
1049 NotifyEditSave(master, this, name);
1051 list.list.Sort(null, 1);
1052 list.list.currentRow = list.list.currentRow;
1054 modifiedDocument = false;
1057 virtual void Window::NotifyEditLoad(EditSection editSection);
1062 for(link = editBoxes.first; link; link = link.next)
1064 FieldDataBox dataBox = link.data;
1067 NotifyEditLoad(master, this);
1069 modifiedDocument = false;
1072 virtual void Window::NotifyEditClear(EditSection editSection);
1077 for(link = editBoxes.first; link; link = link.next)
1079 FieldDataBox dataBox = link.data;
1080 editRow.Select(nil);
1083 NotifyEditClear(master, this);
1084 modifiedDocument = false;
1089 // TO CHECK: Why is there a jump in the scroll thumb size when this is not here?
1092 modifiedDocument = false;