3 define sgs = 3; // screen sgs size
7 extern int __ecereVMethodID_class_OnFree;
8 extern int __ecereVMethodID_class_OnGetString;
11 const char * defaultNameField = "Name";
12 const char * defaultIdField = "Id";
13 const char * defaultActiveField = "Active";
15 public void SetDefaultIdField(const char * value) { defaultIdField = value; }
16 public void SetDefaultNameField(const 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)dataBox.editor : 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)(intptr)new0 byte[type.structSize];
96 ((bool (*)())(void *)r.GetData)(r, nameField, type, (type.type == structClass) ? (void *)(intptr)data : &data);
97 if(type.type == systemClass || type.type == enumClass || type.type == bitClass)
98 s = CopyString(((char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, &data, tempString, null, null));
100 s = CopyString(((char *(*)(void *, void *, char *, void *, bool *))(void *)type._vTbl[__ecereVMethodID_class_OnGetString])(type, (void *)(intptr)data, tempString, null, null));
101 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, (void *)(intptr)data);
102 if(type.type == structClass)
104 void * _data = (void *)(intptr)data;
109 r.GetData(nameField, s);
113 public class TableDropBox : DropBox
115 anchor = { left = 130, top = 180, right = shadowS + sgs * 2 };
133 get { return filter; }
135 property Field nameField { set { nameField = value; } }
136 property uint exclusion { set { exclusion = value; } }
137 property Table table { set { table = value; if(!nameField && value) nameField = value.FindField(defaultNameField); } }
139 virtual void Refill()
144 Field fldId = table.FindField(defaultIdField);
145 if(fldId && nameField)
148 if(filterField && filtered)
150 if(eClass_IsDerived(filterField.type, class(Id)))
152 FieldIndex indexedFields[1];
153 // Table tbl = table.db.OpenTable(table.name, { tableRows });
154 const char * name = table.name;
155 Database db = table.db;
156 Table tbl = db.OpenTable(name, { tableRows });
161 indexedFields[0] = { filterField };
162 tbl.GenerateIndex(1, indexedFields, false);
166 for(r.Find(filterField, middle, nil, filter); !r.nil; r.Next()) //while(r.Next())
170 r.GetData(filterField, idFilter);
171 r.GetData(fldId, id);
172 if(idFilter != filter)
174 if(!exclusion || id != exclusion)
176 String s = GetNameString(r, nameField);
177 AddString(s).tag = id;
183 else if(eClass_IsDerived(filterField.type, class(IdList)))
189 r.GetData(filterField, idList);
190 r.GetData(fldId, id);
191 if(idList && idList.Includes(filter) && (!exclusion || !idList.Includes(exclusion)))
193 String s = GetNameString(r, nameField);
194 AddString(s).tag = id;
206 r.GetData(fldId, id);
209 String s = GetNameString(r, nameField);
210 AddString(s).tag = id;
220 String s = GetNameString(r, nameField);
221 r.GetData(fldId, id);
222 AddString(s).tag = id;
232 property Field filterField { set { filterField = value; } }
234 bool OnKeyHit(Key key, unichar ch)
236 if((SmartKey)key == del)
238 SelectRow(null); //currentRow = null;
241 else if((SmartKey)key == enter)
242 parent.CycleChildren(true, false, false, true);
244 return DropBox::OnKeyHit(key, ch);
247 bool NotifySelect(DropBox dropBox, DataRow row, Modifiers mods)
249 modifiedDocument = true;
259 void EditNotifyCharsAdded()
261 if(!editBox.NotifyUpdate || editBox.NotifyUpdate == EditBox::NotifyUpdate)
262 editBox.NotifyUpdate = EditNotifyUpdate;
265 void EditNotifyUpdate(EditBox editBox)
268 const char * contents = editBox.contents;
269 int len = strlen(contents);
270 if(len && editBox.charPos == len)
272 EditLine line = editBox.firstLine;
275 editBox.GetSelPos(null, null, &x1, null, null, &x2, false);
278 for(row = firstRow; row; row = row.next)
280 const char * string = row.string;
281 if(string && SearchString(string, 0, contents, false, false) == string)
284 editBox.contents = row.string;
285 editBox.SetSelPos(line, 0, len, line, 0, strlen(string));
291 editBox.NotifyUpdate = null;
295 public class DropDataBox : DataBox
300 showNone = false; //true;
304 property uint filter { set { filtered = true; filter = value; } get { return filter; } }
305 property bool filtered { set { filtered = value; } }
306 property uint exclusion { set { exclusion = value; } }
307 property Field filterField { set { filterField = value; } }
308 property Field nameField { set { nameField = value; } }
309 virtual void TableDropBox::RefillFunction();
310 property bool showNone { set { showNone = value; } }
316 TableDropBox dropBox = (TableDropBox) editor;
317 uint id = data ? *(uint *)data : MAXDWORD;
318 void * notifyChanged = (void *)NotifyChanged;
320 OnConfigure(dropBox);
322 NotifyChanged = null;
324 NotifyChanged = notifyChanged;
326 if(id != MAXDWORD) dropBox.SelectRow(dropBox.FindSubRow(id));
330 void OnConfigure(TableDropBox dropBox)
332 if(RefillFunction != DropDataBox::RefillFunction) dropBox.Refill = RefillFunction;
333 if(nameField) dropBox.nameField = nameField;
334 if(filterField) dropBox.filterField = filterField;
336 dropBox.filter = filter;
338 dropBox.filtered = false;
340 dropBox.exclusion = exclusion;
341 dropBox.showNone = showNone;
353 public class EditDropDataBox : DropDataBox
355 void OnConfigure(TableDropBox dropBox)
357 DropDataBox::OnConfigure(dropBox);
358 dropBox.editText = true;
359 dropBox.editBox.NotifyCharsAdded = (void *)TableDropBox::EditNotifyCharsAdded;
363 public class FieldDataBox : DataBox
366 anchor = { left = 110, right = shadowS + sgs * 2 };
375 property EditSection editor
379 parent = value.editArea;
381 value.AddFieldEditor(this);
391 if(field) type = null;
395 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, (void *)(intptr)dataHolder);
396 if(type.type == structClass)
398 void * dataPtr = (void *)(intptr)dataHolder;
405 dataType = value ? value.type : null;
407 text = field ? field.name : null;
409 if(dataType && dataType.type == structClass)
411 dataHolder = (int64)(intptr)new0 byte[dataType.structSize];
412 data = (void *)(intptr)dataHolder;
414 else if(dataType && (dataType.type == noHeadClass || dataType.type == normalClass))
416 if(eClass_IsDerived(dataType, class(String)))
417 dataHolder = (int64)(intptr)CopyString("");
419 dataHolder = (int64)(intptr)eInstance_New(dataType);
420 data = (void *)&dataHolder;
427 if(!type) type = dataType;
434 SetData(null, false);
436 if(type && (type.type == noHeadClass || type.type == normalClass))
438 if(eClass_IsDerived(type, class(String)))
439 dataHolder = (int64)(intptr)CopyString("");
441 dataHolder = (int64)(intptr)eInstance_New(type);
442 data = (void *)&dataHolder;
453 SetData(null, false);
454 master.modifiedDocument = false;
456 ((bool (*)())(void *)Row::GetData)(row, field, field.type, data);
458 if(!dataHolder && type && (type.type == noHeadClass || type.type == normalClass))
460 if(eClass_IsDerived(type, class(String)))
461 dataHolder = (int64)(intptr)CopyString("");
463 dataHolder = (int64)(intptr)eInstance_New(type);
464 data = (void *)&dataHolder;
476 Class type = field.type;
477 if(!DataBox::SaveData())
480 ((bool (*)())(void *)Row::SetData)(row, field, type,
481 (type.type == noHeadClass || type.type == normalClass) ? *(void **)data : data);
491 bool OnActivate(bool active, Window previous, bool * goOnWithActivation, bool direct)
495 if(modifiedDocument && !DataBox::SaveData())
501 bool OnKeyDown(Key key, unichar ch)
503 if((SmartKey)key == enter)
505 DataBox::OnKeyDown(key, ch);
509 return DataBox::OnKeyDown(key, ch);
512 bool OnKeyHit(Key key, unichar ch)
514 if((SmartKey)key == enter)
515 parent.CycleChildren(true, false, false, true);
517 return DataBox::OnKeyHit(key, ch);
520 bool Window::NotifyChanged(DataBox dataBox, bool closingDropDown)
522 modifiedDocument = true;
526 bool Window::NotifyModified()
528 modifiedDocument = true;
535 SetData(null, false);
539 ((void (*)(void *, void *))(void *)type._vTbl[__ecereVMethodID_class_OnFree])(type, (void *)(intptr)dataHolder);
540 if(type.type == structClass)
542 void * dataPtr = (void *)(intptr)dataHolder;
551 int64 dataHolder; // THERE SEEMS(ED?) TO BE A BUG WHEN ACCESSING row ACROSS .so
555 public class FieldCheckButton : FieldDataBox
558 type = class(CheckBool);
559 // TOCHECK: When not here, the virtual area goes wild (anchor.right is not reset)
563 public class FieldDropDataBox : FieldDataBox
570 property uint filter { set { filtered = true; filter = value; } get { return filter; } }
571 property bool filtered { set { filtered = value; } }
572 property uint exclusion { set { exclusion = value; } }
573 property Field filterField { set { filterField = value; } }
574 property Field nameField { set { nameField = value; } }
575 virtual void TableDropBox::RefillFunction();
576 property bool showNone { set { showNone = value; } }
582 TableDropBox dropBox = (TableDropBox) editor;
583 uint id = data ? *(uint *)data : MAXDWORD;
584 OnConfigure(dropBox);
586 if(id != MAXDWORD) dropBox.SelectRow(dropBox.FindSubRow(id));
590 void OnConfigure(TableDropBox dropBox)
592 if(RefillFunction != FieldDropDataBox::RefillFunction) dropBox.Refill = RefillFunction;
593 if(nameField) dropBox.nameField = nameField;
594 if(filterField) dropBox.filterField = filterField;
596 dropBox.filter = filter;
598 dropBox.filtered = false;
599 dropBox.exclusion = exclusion;
600 dropBox.showNone = showNone;
612 public class EditFieldDropDataBox : FieldDropDataBox
616 void OnConfigure(TableDropBox dropBox)
618 FieldDropDataBox::OnConfigure(dropBox);
619 dropBox.editText = true;
620 dropBox.editBox.NotifyCharsAdded = (void *)TableDropBox::EditNotifyCharsAdded;
625 TableDropBox dropBox = (TableDropBox) editor;
627 if(!dropBox.currentRow && dropBox.contents[0])
629 Row row { dropBox.table };
631 OnAddTextEntry(row, dropBox, dropBox.contents);
636 dropBox.SelectRow(dropBox.FindSubRow(sysID));
638 FieldDataBox::Save();
641 virtual bool OnAddTextEntry(Row row, TableDropBox dropBox, const char * entry)
644 row.SetData(dropBox.nameField, entry);
649 public class ListSection : Group
653 anchor = { left = sgs, top = 32 + sgs * 3, bottom = 55 + sgs * 3 };
655 property EditSection editor
673 FieldIndex indexedFields[1];
675 if(!fldId) fldId = table.FindField(defaultIdField);
676 if(!fldName) fldName = table.FindField(defaultNameField);
677 if(!fldActive) fldActive = table.FindField(defaultActiveField);
679 indexedFields[0] = { fldId };
680 table.Index(1, indexedFields);
682 editor.editRow.tbl = table;
689 Field fldId, fldName, fldActive;
691 virtual DialogResult Window::NotifySaveConfirmation(ListSection listSection)
693 return MessageBox { master = this, type = yesNoCancel, text = $"List Editor", contents = $"You have modified this entry. Would you like to save it before proceeding?" }.Modal();
696 bool OnClose(bool parentClosing)
698 if(editor && editor.modifiedDocument)
700 switch(NotifySaveConfirmation(master, this))
707 editor.modifiedDocument = false;
717 //if(fldId && fldName)
720 NotifyRefillList(master, this, r);
724 editor.modifiedDocument = false;
727 virtual void Window::NotifyRefillList(ListSection listSection, Row r)
729 if(listSection.fldId && listSection.fldName)
731 Class type = listSection.fldName.type;
732 bool stringName = !strcmp(type.dataTypeString, "char *");
737 r.GetData(listSection.fldId, id);
739 r.GetData(listSection.fldName, s);
742 s = GetNameString(r, listSection.fldName);
743 // s = PrintString("Entry ", id);
745 listSection.list.AddString(s).tag = id;
751 virtual bool Window::NotifyNew(ListSection listSection, Row r);
755 this, anchor = { right = shadowS + sgs * 2, top = 24 }, hotKey = altW, text = $"New";
757 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
759 list.NotifySelect(this, list, null, 0);
760 if(!editor.modifiedDocument)
762 uint id; // = table.rowsCount + 1; // this is bad with deleted rows, won't work, how to have unique id?
765 if(r.Last()) // this will reuse ids in cases where the item(s) with the last id have been deleted
767 r.GetData(fldId, id);
778 // Patch for SQLite driver which auto-increments IDs
780 if(r.GetData(fldId, curID))
783 r.SetData(fldId, id);
785 if(!strcmp(fldName.type.dataTypeString, "char *"))
786 r.SetData(fldName, $"[New]");
789 r.SetData(fldActive, active);
791 if(NotifyNew(master, this, r))
792 list.currentRow = list.AddString($"[New]");
797 list.currentRow.tag = id;
798 SelectListRow(list.currentRow);
805 virtual bool Window::NotifyDeleteConfirmation(ListSection listSection)
807 return MessageBox { master = this, type = yesNo, text = $"List Editor",
808 contents = $"You are about to delete an entry.\n"
809 "Do you wish to continue?"
813 virtual void Window::NotifyDeleting(ListSection listSection);
814 virtual void Window::NotifyDeleted(ListSection listSection);
816 ButtonStyle btnDelete
818 this, anchor = { right = shadowS + sgs * 2, top = 24 }, hotKey = altD, text = $"Delete";
820 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
824 if(NotifyDeleteConfirmation(master, this))
826 NotifyDeleting(master, this);
828 editor.editRow.Delete();
829 list.DeleteRow(list.currentRow);
832 NotifyDeleted(master, this);
834 SelectListRow(list.currentRow);
842 bool FilterNotifyChanged(DataBox dataBox, bool closeDropDown)
847 SelectListRow(list.firstRow);
854 this, anchor = { left = sgs * 2, top = 22 + 22 + sgs * 4, right = shadowS + sgs * 2, bottom = shadowS + sgs * 2 };
855 alwaysHighLight = true;
857 bool NotifySelect(ListBox listBox, DataRow row, Modifiers mods)
860 if(/*row && */row != lastRow)
862 if(editor.modifiedDocument)
865 list.currentRow = lastRow;
867 switch(NotifySaveConfirmation(master, this))
874 editor.modifiedDocument = false;
875 list.currentRow = row;
885 virtual void Window::NotifySelectListRow(ListSection listSection, uint64 id);
887 void SelectListRow(DataRow row)
889 // Time startTime = GetTime();
895 if(list.currentRow != row)
896 list.currentRow = row;
897 if(editor.editRow.Find(fldId, middle, nil, id))
899 editor.listRow = row;
900 NotifySelectListRow(master, this, id);
904 // Logf("SelectListRow took %f seconds\n", GetTime() - startTime);
910 SelectListRow(list.firstRow);
918 editor.btnSave.disabled = !list.currentRow;
919 editor.btnReload.disabled = !list.currentRow;
920 btnDelete.disabled = !list.currentRow;
921 editor.disabled = !list.firstRow;
925 void OnResize(int width, int height)
927 int x = width - btnDelete.size.w - 20;
929 btnDelete.position.x = x;
931 btnNew.position.x = x = x - btnNew.size.w - sgs * 2;
934 bool OnPostCreate(void)
936 OnResize(clientSize.w, clientSize.h);
938 if(editor) editor.modifiedDocument = false;
939 return Window::OnPostCreate();
948 public class EditSection : Group
953 anchor = { right = sgs, top = 32 + sgs * 3, bottom = 55 + sgs * 3 };
957 editBoxes.Free(null);
978 OldList editBoxes { };
980 Window editArea { this, borderStyle = deep, tabCycle = true, anchor = { left = 8, top = 54, right = 10, bottom = 10 }, hasVertScroll = true, dontHideScroll = true };
984 this, anchor = { right = shadowS + sgs * 2, top = 24 }, hotKey = altV, text = $"Save";
986 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
993 ButtonStyle btnReload
995 this, anchor = { left = 10, top = 24 }, hotKey = altV, text = $"Revert";
997 bool NotifyClicked(Button button, int x, int y, Modifiers mods)
1005 void AddFieldEditor(FieldDataBox box)
1007 editBoxes.Add(OldLink { data = box });
1010 virtual void Window::NotifyInitFields(EditSection editSection);
1015 for(link = editBoxes.first; link; link = link.next)
1017 FieldDataBox dataBox = link.data;
1020 NotifyInitFields(master, this);
1025 modifiedDocument = false;
1028 virtual void Window::NotifyEditSave(EditSection edit, String name)
1030 edit.listRow.string = name;
1035 bool stringName = !strcmp(list.fldName.type.dataTypeString, "char *");
1039 editRow.tbl.db.Begin();
1040 for(link = editBoxes.first; link; link = link.next)
1042 FieldDataBox dataBox = link.data;
1045 editRow.tbl.db.Commit();
1046 // ADDED THIS HERE FOR SQLITE TO REFRESH
1047 editRow.Find(list.fldId, middle, nil, list.list.currentRow.tag);
1050 editRow.GetData(list.fldName, name);
1052 name = PrintString("Entry ", list.list.currentRow.tag);
1054 NotifyEditSave(master, this, name);
1056 list.list.Sort(null, 1);
1057 list.list.currentRow = list.list.currentRow;
1059 modifiedDocument = false;
1062 virtual void Window::NotifyEditLoad(EditSection editSection);
1067 for(link = editBoxes.first; link; link = link.next)
1069 FieldDataBox dataBox = link.data;
1072 NotifyEditLoad(master, this);
1074 modifiedDocument = false;
1077 virtual void Window::NotifyEditClear(EditSection editSection);
1082 for(link = editBoxes.first; link; link = link.next)
1084 FieldDataBox dataBox = link.data;
1085 editRow.Select(nil);
1088 NotifyEditClear(master, this);
1089 modifiedDocument = false;
1094 // TO CHECK: Why is there a jump in the scroll thumb size when this is not here?
1097 modifiedDocument = false;